FlyWithLua Quick Reference Manual Fly With Lua En

FlyWithLua_Manual_en

User Manual:

Open the PDF directly: View PDF PDF.
Page Count: 129

DownloadFlyWithLua Quick Reference Manual Fly With Lua En
Open PDF In BrowserView PDF
FlyWithLua V2.7 NG Reference Manual
Carsten Lynker
March 12, 2019

Contents

Contents

Contents
1

Using the Plugin

1.1
1.2
1.3
1.4
1.5
1.6
1.7
1.8
1.9
1.10
2

11

What’s needed . . . . . . . . . . . . . . . . . . . . . . . . .
Difference between Core, Complete, NG and Source Edition
Installation . . . . . . . . . . . . . . . . . . . . . . . . . .
How to interact with Lua . . . . . . . . . . . . . . . . . . .
Lua variables and DataRefs . . . . . . . . . . . . . . . . . .
Writing a first config file . . . . . . . . . . . . . . . . . . .
Pre-defined variables . . . . . . . . . . . . . . . . . . . . .
Loop Callbacks . . . . . . . . . . . . . . . . . . . . . . . .
Menu entries . . . . . . . . . . . . . . . . . . . . . . . . .
Menu switches . . . . . . . . . . . . . . . . . . . . . . . .

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

Reference

2.1

11
12
13
14
14
15
15
15
16
16
18

Predefined variables . . . . . . . . . . . . .
2.1.1 LONGITUDE . . . . . . . . . . .
2.1.2 LATITUDE . . . . . . . . . . . . .
2.1.3 PLANE_ICAO . . . . . . . . . . .
2.1.4 PLANE_TAILNUMBER . . . . . .
2.1.5 SCREEN_WIDTH . . . . . . . . .
2.1.6 SCREEN_HIGHT . . . . . . . . .
2.1.7 MOUSE_X . . . . . . . . . . . . .
2.1.8 MOUSE_Y . . . . . . . . . . . . .
2.1.9 XSB_METAR . . . . . . . . . . .
2.1.10 LUA_RUN . . . . . . . . . . . . .
2.1.11 XPLANE_VERSION . . . . . . .
2.1.12 XPLANE_HOSTID . . . . . . . .
2.1.13 SDK_VERSION . . . . . . . . . .
2.1.14 SYSTEM . . . . . . . . . . . . . .
2.1.15 SYSTEM_ARCHITECTURE . . .
2.1.16 XPLANE_LANGUAGE . . . . . .
2.1.17 DIRECTORY_SEPARATOR . . .
2.1.18 SYSTEM_DIRECTORY . . . . . .
2.1.19 SCRIPT_DIRECTORY . . . . . .
2.1.20 INTERNALS_DIRECTORY . . . .
2.1.21 MODULES_DIRECTORY . . . . .
2.1.22 AIRCRAFT_PATH . . . . . . . . .
2.1.23 AIRCRAFT_FILENAME . . . . .
2.1.24 DO_EVERY_FRAME_TIME_SEC

Page 2 of 129

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

18
18
18
18
18
18
18
19
19
19
19
19
19
19
20
20
20
21
21
21
21
21
22
22
22

Contents

2.2

Contents
2.1.25 DO_EVERY_DRAW_TIME_SEC . . . . . . . . . . . . . . . . . . . . 22
2.1.26 DO_SOMETIMES_TIME_SEC . . . . . . . . . . . . . . . . . . . . . 22
2.1.27 DO_OFTEN_TIME_SEC . . . . . . . . . . . . . . . . . . . . . . . . 22
2.1.28 SCRIPTS_LOADING_TIME_SEC . . . . . . . . . . . . . . . . . . . 22
2.1.29 CLOCKS_PER_SEC . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
2.1.30 LUA_MEMORY_USAGE_KB . . . . . . . . . . . . . . . . . . . . . 22
Lua functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
2.2.1 DataRef( "variable name", "DataRef name" ) . . . . . . . . . . . . . . 23
2.2.2 DataRef( "variable name", "DataRef name", "readonly" ) . . . . . . . . 23
2.2.3 DataRef( "variable name", "DataRef name", "readonly", index ) . . . . 23
2.2.4 table = dataref_table( "DataRef name") . . . . . . . . . . . . . . . . . 24
2.2.5 define_shared_DataRef("DataRef name", "DataRef type") . . . . . . . 24
2.2.6 table = create_dataref_table( "DataRef name", "DataRef type") . . . . . 24
2.2.7 DataRef name, Index, readonly, DataRef type, DataRef ID = get_DataRef_binding(
"variable name" ) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
2.2.8 button( button number ) . . . . . . . . . . . . . . . . . . . . . . . . . 25
2.2.9 last_button( button number ) . . . . . . . . . . . . . . . . . . . . . . . 25
2.2.10 create_switch( button number, DataRef name, index, off value, on value ) 26
2.2.11 create_positive_edge_flip( button number, DataRef name, index, first
value, second value ) . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
2.2.12 create_negative_edge_flip( button number, DataRef name, index, first
value, second value ) . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
2.2.13 create_positive_edge_trigger( button number, DataRef name, index, value
) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
2.2.14 create_negative_edge_trigger( button number, DataRef name, index, value
) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
2.2.15 create_positive_edge_increment( button number, DataRef name, index,
stepping, limit, rounding ) . . . . . . . . . . . . . . . . . . . . . . . . 28
2.2.16 create_negative_edge_increment( button number, DataRef name, index,
stepping, limit, rounding ) . . . . . . . . . . . . . . . . . . . . . . . . 28
2.2.17 create_positive_edge_decrement( button number, DataRef name, index,
stepping, limit, rounding ) . . . . . . . . . . . . . . . . . . . . . . . . 29
2.2.18 create_negative_edge_decrement( button number, DataRef name, index,
stepping, limit, rounding ) . . . . . . . . . . . . . . . . . . . . . . . . 29
2.2.19 create_axis_median( axis number, variable name ) . . . . . . . . . . . 29
2.2.20 get( "DataRef name" ) . . . . . . . . . . . . . . . . . . . . . . . . . . 29
2.2.21 get( "DataRef name", index ) . . . . . . . . . . . . . . . . . . . . . . . 30
2.2.22 set( "DataRef name", value ) . . . . . . . . . . . . . . . . . . . . . . . 31
2.2.23 set_array( "DataRef name", index, value ) . . . . . . . . . . . . . . . . 31
2.2.24 set_button_assignment( button number, "simulator function") . . . . . 31
2.2.25 set_axis_assignment( axis number, "axis function", "reverse") . . . . . 32
2.2.26 clear_all_axis_assignments() . . . . . . . . . . . . . . . . . . . . . . . 32
2.2.27 clear_all_button_assignments() . . . . . . . . . . . . . . . . . . . . . 32
2.2.28 set_pilots_head( x, y, z, heading, pitch ) . . . . . . . . . . . . . . . . . 32

Page 3 of 129

Contents

Contents
2.2.29
2.2.30
2.2.31
2.2.32
2.2.33
2.2.34
2.2.35
2.2.36
2.2.37
2.2.38
2.2.39
2.2.40
2.2.41
2.2.42
2.2.43
2.2.44
2.2.45
2.2.46
2.2.47
2.2.48
2.2.49
2.2.50
2.2.51
2.2.52
2.2.53
2.2.54
2.2.55
2.2.56
2.2.57
2.2.58
2.2.59
2.2.60
2.2.61
2.2.62
2.2.63
2.2.64
2.2.65
2.2.66
2.2.67
2.2.68
2.2.69
2.2.70

x, y, z, heading, pitch = get_pilots_head( ) . . . . . . . . . . . . . . . .
command_begin( "simulator function" ) . . . . . . . . . . . . . . . . .
command_once( "simulator function" ) . . . . . . . . . . . . . . . . .
command_end( "simulator function" ) . . . . . . . . . . . . . . . . . .
logMsg( "string" ) . . . . . . . . . . . . . . . . . . . . . . . . . . . .
XSBSpeakString( "string" ) . . . . . . . . . . . . . . . . . . . . . . .
XPLMSpeakString( "string" ) . . . . . . . . . . . . . . . . . . . . . .
print( "string" ) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
do_sometimes( "Lua code string" ) . . . . . . . . . . . . . . . . . . .
do_often( "Lua code string" ) . . . . . . . . . . . . . . . . . . . . . .
do_every_frame( "Lua code string" ) . . . . . . . . . . . . . . . . . .
do_every_draw( "Lua code string" ) . . . . . . . . . . . . . . . . . . .
do_on_keystroke( "Lua code string" ) . . . . . . . . . . . . . . . . . .
do_on_mouse_wheel( "Lua code string" ) . . . . . . . . . . . . . . . .
do_on_mouse_click( "Lua code string" ) . . . . . . . . . . . . . . . .
do_on_new_metar( "Lua code string" ) . . . . . . . . . . . . . . . . .
do_on_new_XSB_text( "Lua code string" ) . . . . . . . . . . . . . . .
do_on_exit( "Lua code string" ) . . . . . . . . . . . . . . . . . . . . .
draw_string( x, y, "string" ) . . . . . . . . . . . . . . . . . . . . . . . .
draw_string( x, y, "string", "color" ) . . . . . . . . . . . . . . . . . . .
draw_string( x, y, "string", red, green, blue ) . . . . . . . . . . . . . . .
draw_string_Helvetica_10( x, y, "string" ) . . . . . . . . . . . . . . . .
draw_string_Helvetica_12( x, y, "string" ) . . . . . . . . . . . . . . . .
draw_string_Helvetica_18( x, y, "string" ) . . . . . . . . . . . . . . . .
draw_string_Times_Roman_10( x, y, "string" ) . . . . . . . . . . . . .
draw_string_Times_Roman_24( x, y, "string" ) . . . . . . . . . . . . .
measure_string( "string" ) . . . . . . . . . . . . . . . . . . . . . . . .
measure_string( "string", "font name" ) . . . . . . . . . . . . . . . . .
hight, width = bubble( x, y, "title", . . . ) . . . . . . . . . . . . . . . . .
hight, width = big_bubble( x, y, "title", . . . ) . . . . . . . . . . . . . . .
hight, width = huge_bubble( x, y, "title", . . . ) . . . . . . . . . . . . . .
add_macro( "macro name", "Lua code string" ) . . . . . . . . . . . . .
add_ATC_macro( "macro name", "Lua code string" ) . . . . . . . . . .
add_macro( "macro name", "activation code string", "deactivation code
string", "default state" ) . . . . . . . . . . . . . . . . . . . . . . . . .
create_command( "command name", "command description", "begin code
string", "continue code string", "end code string" ) . . . . . . . . . . .
table = directory_to_table( "path" ) . . . . . . . . . . . . . . . . . . .
place_aircraft_at( "ICAO" ) . . . . . . . . . . . . . . . . . . . . . . . .
load_aircraft( "path and full filename" ) . . . . . . . . . . . . . . . . .
load_situation( "path and full filename" ) . . . . . . . . . . . . . . . .
save_situation( "path and full filename" ) . . . . . . . . . . . . . . . .
reload_scenery() . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
crash_the_sim() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Page 4 of 129

33
33
33
33
34
34
34
35
35
35
35
35
36
36
37
37
37
38
38
38
39
39
39
39
39
40
40
40
40
40
41
41
41
41
42
42
43
43
43
43
44
44

Contents
3

Modules

3.1
3.2

3.3
4

45

The Radio Module . . . . . . . . . . . . . . . . . . .
The XSquawkBox Module . . . . . . . . . . . . . . .
3.2.1 XSBConnect() . . . . . . . . . . . . . . . . .
3.2.2 XSBUserLogin() . . . . . . . . . . . . . . . .
3.2.3 XSBDisconnect() . . . . . . . . . . . . . . . .
3.2.4 XSBShowFlightplan() . . . . . . . . . . . . .
3.2.5 XSBSendFlightplan() . . . . . . . . . . . . . .
3.2.6 frequency = XSBLookupATC( "name string" )
The Bit Module . . . . . . . . . . . . . . . . . . . . .

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

OpenAL sound

4.1
4.2

4.3

5

Contents

48

Buffers, Sounds and Listeners . . . . . . . . . . . . .
Loading and defining sounds . . . . . . . . . . . . . .
4.2.1 table position = load_WAV_file( filename ) . .
4.2.2 let_sound_loop( table position, boolean value )
4.2.3 set_sound_pitch( table position, float value ) .
4.2.4 set_sound_gain( table position, float value ) . .
4.2.5 unload_all_sounds( ) . . . . . . . . . . . . . .
4.2.6 replace_WAV_file(table position, filename ) . .
Using the sounds from the sound table . . . . . . . . .
4.3.1 play_sound( table position ) . . . . . . . . . .
4.3.2 stop_sound( table position ) . . . . . . . . . .
4.3.3 pause_sound( table position ) . . . . . . . . .
4.3.4 rewind_sound( table position ) . . . . . . . . .

OpenGL graphics

5.1

45
46
46
46
46
47
47
47
47

48
48
48
49
49
49
49
50
51
51
51
51
51
52

Functions of OpenGL . . . . . . . . . . .
5.1.1 glBegin_POINTS() . . . . . . . .
5.1.2 glBegin_LINES() . . . . . . . . .
5.1.3 glBegin_LINE_STRIP() . . . . .
5.1.4 glBegin_LINE_LOOP() . . . . .
5.1.5 glBegin_POLYGON() . . . . . .
5.1.6 glBegin_TRIANGLES() . . . . .
5.1.7 glBegin_TRIANGLE_STRIP() .
5.1.8 glBegin_TRIANGLE_FAN() . . .
5.1.9 glBegin_QUADS() . . . . . . . .
5.1.10 glBegin_QUAD_STRIP() . . . .
5.1.11 glEnd() . . . . . . . . . . . . . .
5.1.12 glVertex2f(x, y) . . . . . . . . . .
5.1.13 glVertex3f(x, y, z) . . . . . . . .
5.1.14 glLineWidth(width) . . . . . . .
5.1.15 glColor3f(red, green, blue) . . . .
5.1.16 glColor4f(red, green, blue, alpha)

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

Page 5 of 129

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

52
52
52
52
52
52
52
52
52
52
52
52
52
52
53
53
53

Contents

Contents
5.1.17 glRectf(x1, y1, x2, y2) . . . . . . . . . . . . . . . . . . . . . . . . . .
5.1.18 XPLMSetGraphicsState(EnableFog, NumberTexUnits, EnableLighting,
EnableAlphaTesting, EnableAlphaBlending, EnableDepthTesting, EnableDepthWriting) . . . . . . . . . . . . . . . . . . . . . . . . . . . .

6

7

8

53

53

The graphics module

54

6.1

54
54
54
54
54
55
55
55

Functions of graphics module . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.1.1 x_result, y_result = graphics.move_angle( x, y, angle, length ) . . . . .
6.1.2 graphics.draw_line( x1, y1, x2, y2 ) . . . . . . . . . . . . . . . . . . .
6.1.3 graphics.draw_rectangle( x1, y1, x2, y2 ) . . . . . . . . . . . . . . . . .
6.1.4 graphics.draw_triangle( x1, y1, x2, y2, x3, y3 ) . . . . . . . . . . . . .
6.1.5 graphics.set_color( red, green, blue, alpha ) . . . . . . . . . . . . . . .
6.1.6 graphics.set_width( width ) . . . . . . . . . . . . . . . . . . . . . . . .
6.1.7 graphics.draw_angle_line( x, y, angle, length ) . . . . . . . . . . . . .
6.1.8 graphics.draw_angle_arrow( x, y, angle, length, arrowhead’s length, line
width ) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.1.9 graphics.draw_circle( x, y, radius, line width ) . . . . . . . . . . . . . .
6.1.10 graphics.draw_filled_circle( x, y, radius ) . . . . . . . . . . . . . . . .
6.1.11 graphics.draw_arc( x, y, start angle, end angle, radius, line width ) . . .
6.1.12 graphics.draw_filled_arc( x, y, start angle, end angle, radius ) . . . . .
6.1.13 graphics.draw_tick_mark( x, y, angle, radius, length, width ) . . . . . .
6.1.14 graphics.draw_outer_tracer( x, y, angle, radius, size ) . . . . . . . . . .
6.1.15 graphics.draw_inner_tracer( x, y, angle, radius, size ) . . . . . . . . . .

55
56
56
56
56
56
56
57

HUD module

58

7.1
7.2
7.3

58
58
61
61
61
61
62

An Interactive HUD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
An Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Functions from HUD module . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.3.1 HUD.begin_HUD( x, y, width, hight, "name", "always" ) . . . . . . . .
7.3.2 HUD.end_HUD( ) . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.3.3 HUD.create_element( "name", x, y, width, hight, red, green, blue, alpha )
7.3.4 HUD.draw_string( x, y, fontsize, "string", red, green, blue, alpha ) . . .
7.3.5 HUD.draw_fstring( x, y, fontsize, "format", "expression", red, green,
blue, alpha ) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.3.6 HUD.create_backlight_indicator( x, y, width, hight, "condition", red,
green, blue, alpha ) . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.3.7 HUD.create_click_action( x, y, width, hight, "action" ) . . . . . . . . .
7.3.8 HUD.create_click_switch( x, y, width, hight, "variable", value, alternative value ) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.3.9 HUD.create_wheel_action( x, y, width, hight, "action" ) . . . . . . . .

62
62
63
63
64

XPLMNavigation

65

8.1

65
65

Functions from XPLMNavigation . . . . . . . . . . . . . . . . . . . . . . . .
8.1.1 nav_reference = XPLMGetFirstNavAid() . . . . . . . . . . . . . . . .

Page 6 of 129

Contents

Contents
8.1.2
8.1.3
8.1.4
8.1.5
8.1.6
8.1.7
8.1.8
8.1.9
8.1.10
8.1.11
8.1.12
8.1.13
8.1.14
8.1.15

9

next_nav_reference = XPLMGetNextNavAid( inNavAidRef ) . . . . .
first_nav_reference = XPLMFindFirstNavAidOfType( inType ) . . . .
last_nav_reference = XPLMFindLastNavAidOfType( inType ) . . . . .
nav_reference = XPLMFindNavAid( inNameFragment, inIDFragment,
inLat, inLon, inFrequency, inType) . . . . . . . . . . . . . . . . . . .
outType, outLatitude, outLongitude, outHeight, outFrequency, outHeading, outID, outName = XPLMGetNavAidInfo( inRef ) . . . . . . . . .
index_count = XPLMCountFMSEntries() . . . . . . . . . . . . . . . .
index = XPLMGetDisplayedFMSEntry() . . . . . . . . . . . . . . . .
index = XPLMGetDestinationFMSEntry() . . . . . . . . . . . . . . . .
XPLMSetDisplayedFMSEntry( inIndex ) . . . . . . . . . . . . . . . .
XPLMSetDestinationFMSEntry( inIndex ) . . . . . . . . . . . . . . .
outType, outID, outRef, outAltitude, outLat, outLon = XPLMGetFMSEntryInfo( inIndex ) . . . . . . . . . . . . . . . . . . . . . . . . . . .
XPLMSetFMSEntryInfo( inIndex, inRef, inAltitude) . . . . . . . . . .
XPLMSetFMSEntryLatLon( inIndex, inLat, inLon, inAltitude) . . . . .
XPLMClearFMSEntry( inIndex ) . . . . . . . . . . . . . . . . . . . .

65
65
65
65
65
65
65
65
65
65
65
66
66
66

Access HID devices

67

9.1

67
67
67
67
67
68
68
68
69
69
69
69
70

9.2

9.3

Pre-defined variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
9.1.1 NUMBER_OF_HID_DEVICES . . . . . . . . . . . . . . . . . . . . .
9.1.2 ALL_HID_DEVICES . . . . . . . . . . . . . . . . . . . . . . . . . .
HID related functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
9.2.1 table, number = create_HID_table() . . . . . . . . . . . . . . . . . . .
9.2.2 device = hid_open( vendor_ID, product_ID ) . . . . . . . . . . . . . .
9.2.3 device = hid_open_path( path ) . . . . . . . . . . . . . . . . . . . . . .
9.2.4 hid_close( device ) . . . . . . . . . . . . . . . . . . . . . . . . . . . .
9.2.5 hid_write( device, report ID, value, ... ) . . . . . . . . . . . . . . . . .
9.2.6 nov, variable, ... = hid_read_timeout( device, nov wanted, milliseconds )
9.2.7 nov, variable, ... = hid_read_timeout( device, nov wanted ) . . . . . . .
9.2.8 success = hid_set_nonblocking( device, nonblock ) . . . . . . . . . . .
9.2.9 nobw = hid_send_feature_report( device, report ID, value, ... ) . . . . .
9.2.10 nobw = hid_send_filled_feature_report( device, report ID, nobts, value,
... ) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
9.2.11 nobr, report ID, variable, ... = hid_get_feature_report( device, novw ) .
The Arcaze USB module . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
9.3.1 device = arcaze.open_first_device() . . . . . . . . . . . . . . . . . . .
9.3.2 A1, A2, A3, ..., B19, B20 = arcaze.read_pins( device ) . . . . . . . . .
9.3.3 ADC1, ADC2, ADC3, ADC4, ADC5, ADC6 = arcaze.read_ADCs( device ) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
9.3.4 E1, E2, E3, ..., E19, E20 = arcaze.read_encoders( device ) . . . . . . .
9.3.5 arcaze.set_all_pins_for_input( device ) . . . . . . . . . . . . . . . . .
9.3.6 arcaze.set_pin_direction( device, pin, direction ) . . . . . . . . . . . .
9.3.7 arcaze.set_pin( device, pin, value ) . . . . . . . . . . . . . . . . . . . .

Page 7 of 129

70
71
71
72
72
73
73
73
74
74

Contents

Contents
9.3.8 arcaze.init_display( device, address, intensity, scan_limit ) . . . . . . .
9.3.9 arcaze.init_display( device, address ) . . . . . . . . . . . . . . . . . .
9.3.10 arcaze.show( device, address, mask, value_string ) . . . . . . . . . . .

10 Classic and modern mode

76

10.1 Reading classic functions . . . . . . . . . . . . . . . . . . . . . . . . . .
10.1.1 variable = XPLMGetDatai( DataRef ) . . . . . . . . . . . . . . .
10.1.2 variable = XPLMGetDataf( DataRef ) . . . . . . . . . . . . . . .
10.1.3 variable = XPLMGetDatad( DataRef ) . . . . . . . . . . . . . .
10.1.4 table = XPLMGetDatavi( DataRef, inIndex, inMax ) . . . . . . .
10.1.5 table = XPLMGetDatavf( DataRef ) . . . . . . . . . . . . . . . .
10.1.6 userdata variable = XPLMFindDataRef( DataRef Name ) . . . .
10.1.7 datatype variable = XPLMGetDataRefTypes( DataRef reference )
10.2 Writing classic functions . . . . . . . . . . . . . . . . . . . . . . . . . .
10.2.1 XPLMSetDatai( DataRef, variable or value) . . . . . . . . . . .
10.2.2 XPLMSetDataf( DataRef, variable or value) . . . . . . . . . . .
10.2.3 XPLMSetDatad( DataRef, variable or value) . . . . . . . . . . .
10.2.4 XPLMSetDatavi( DataRef, table, inIndex, inMax ) . . . . . . . .
10.2.5 XPLMSetDatavf( DataRef, table, inIndex, inMax ) . . . . . . . .

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

11 The Lua way to access DataRefs

76
76
77
77
77
77
78
78
80
80
80
80
80
81
81

11.1 A magic metatable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
11.1.1 table = dataref_table( DataRef ) . . . . . . . . . . . . . . . . . . . . .
12 Manage your joysticks

12.1
12.2
12.3
12.4

74
75
75

81
82
83

Get a basic configuration . . . .
Define your sticks . . . . . . . .
Define type specific assignments
Lua for cockpit builders . . . . .

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

83
84
84
85

13 Understanding PLCs

87

14 Basic knowledge about DataRefs

89

14.1
14.2
14.3
14.4

What are DataRefs? . .
Find the right DataRefs
Accessing DataRefs . .
Observe the DataRef .

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

Strings inside of strings .
Multiple line strings . . .
Global or local variables?
Tables are tables . . . . .

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

15 Take Lua into consideration

15.1
15.2
15.3
15.4

89
89
90
91
93

16 FlyWithLua 2.7.x Added New Features

Page 8 of 129

93
94
94
95
96

Contents

Contents

17 Floating Windows

101

17.1
17.2
17.3
17.4
17.5
17.6
17.7
17.8
17.9
17.10
17.11
17.12
17.13
17.14
17.15
17.16

demo_floating_wnd = float_wnd_create(800,450,1,false) . . . . . . . . . . . . 101
float_wnd_set_title(demo_floating_wnd, "floating window Demo") . . . . . . 101
float_wnd_set_position(demo_floating_wnd, 775, 650) . . . . . . . . . . . . . 102
float_wnd_set_ondraw(demo_floating_wnd, "on_draw_floating_window") . . 102
float_wnd_set_onclick(demo_floating_wnd, "on_click_floating_window") . . 102
float_wnd_set_onclose(demo_floating_wnd, "on_close_floating_window") . . 102
xplm_wnd = float_wnd_get_xplm_handle(demo_floating_wnd) . . . . . . . . 102
function on_draw_floating_window(demo_floating_wnd, x3, y3) . . . . . . . 103
function on_click_floating_window(demo_floating_wnd, x3, y3) . . . . . . . 103
function on_close_floating_window(demo_floating_wnd) . . . . . . . . . . . 103
is_popped = float_wnd_is_popped(fwl_wnd) . . . . . . . . . . . . . . . . . . 104
is_visible = float_wnd_get_visible(fwl_wnd) . . . . . . . . . . . . . . . . . . 104
is_front = float_wnd_is_front(fwl_wnd) . . . . . . . . . . . . . . . . . . . . . 104
is_vr = float_wnd_is_vr(fwl_wnd) . . . . . . . . . . . . . . . . . . . . . . . . 104
function float_wnd_bring_to_front(fwl_wnd) . . . . . . . . . . . . . . . . . . 104
function float_wnd_set_resizing_limits(fwl_wnd, minWidth, minHeight, maxWidth,
maxHeight) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
17.17 function float_wnd_set_positioning_mode(fwl_wnd, 1, -1) . . . . . . . . . . . 105
17.18 function float_wnd_set_gravity(fwl_wnd, gLeft, gTop, gRight, gBottom) . . . 105
17.19 function float_wnd_set_geometry(fwl_wnd, nLeft, nTop, nRight, nBottom) . . 106
17.20 function float_wnd_set_geometry(fwl_wnd, pLeft, pTop, pRight, pBottom) . . 106
17.21 function float_wnd_set_geometry(fwl_wnd, vrWidth, vrHeight) . . . . . . . . 107
17.22 nwinLeft, nwinTop, nwinRight, nwinBottom = float_wnd_get_geometry(fwl_wnd)108
17.23 pwinLeft, pwinTop, pwinRight, pwinBottom = float_wnd_get_geometry(fwl_wnd)109
17.24 vrwinWidth, vrwinHeight = float_wnd_get_geometry(fwl_wnd) . . . . . . . . 109
17.25 msgx, msgy = XPLMGetMouseLocationGlobal() . . . . . . . . . . . . . . . . 110
17.26 ssWidth, ssHeight = XPLMGetScreenSize() . . . . . . . . . . . . . . . . . . . 110
17.27 bLeft, bTop, bRight, bBottom = XPLMGetScreenBoundsGlobal() . . . . . . . 111
17.28 tOS = XPLMGetAllMonitorBoundsOS() . . . . . . . . . . . . . . . . . . . . 112
17.29 tGB = XPLMGetAllMonitorBoundsGlobal() . . . . . . . . . . . . . . . . . . 112
18 Imgui Windows

18.1
18.2
18.3
18.4
18.5
18.6
18.7
18.8

113

demo_wnd = float_wnd_create(800, 450, 1, true) . . . . . .
float_wnd_set_title(demo_wnd, "Demo Window") . . . . . .
float_wnd_set_position(demo_wnd, 775, 650) . . . . . . . .
float_wnd_set_imgui_builder(demo_wnd, "build_demo") . .
float_wnd_set_onclose(demo_wnd, "closed_demo") . . . . .
image_id = float_wnd_load_image(SCRIPT_DIRECTORY ..
function build_demo(wnd, x, y) . . . . . . . . . . . . . . .
function closed_demo(wnd) . . . . . . . . . . . . . . . . .

19 Debugging

. . . . . . . . . . 113
. . . . . . . . . . 113
. . . . . . . . . . 114
. . . . . . . . . . 114
. . . . . . . . . . 114
"/imgui_demo.jpg")115
. . . . . . . . . . 115
. . . . . . . . . . 115
116

Page 9 of 129

Contents

Contents

20 Integrate foreign libraries

117

21 Statically linking lib’s into FlyWithLua plugin binary.

118

22 LuaXML

119

23 Luasocket

119

24 Sol2

119

25 Scripts (Quarantine) folder

120

26 fwl_prefs.ini file

121

27 The new 64-bit architecture

122

27.1 Architecture exclusive script loading . . . . . . . . . . . . . . . . . . . . . . . 122
27.2 Checking architecture inside a script . . . . . . . . . . . . . . . . . . . . . . . 122
27.3 64-bit DLLs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
28 Q&A

123

28.1 My script doesn’t work. What can I do? . . . . . .
28.1.1 Check the debug info file and Log.txt . . .
28.1.2 Check for conflicts to other scripts . . . . .
28.1.3 I really can’t solve it! . . . . . . . . . . . .
28.2 How to ask the developer of FlyWithLua for help? .
28.3 Is the debug file privacy safe? . . . . . . . . . . . .
28.4 Where are the Splines? . . . . . . . . . . . . . . .
28.5 Feature requests . . . . . . . . . . . . . . . . . . .
28.6 Can I store Lua files inside the aircraft’s folder? . .
28.7 I want full access to X-Plane’s plugin SDK! . . . .
28.8 Using Lua For Windows . . . . . . . . . . . . . .

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

123
123
123
123
124
124
124
125
125
126
127

29 Credits

128

30 License

129

Page 10 of 129

1

USING THE PLUGIN

1 Using the Plugin
1.1 What’s needed

To use FlyWithLua, you will need following:
a) The plugin itself.
b) A nice text editor (VIM, GNU Emacs, Notepad++, ...).
c) The plugin »XSquawkBox« (optional, but usefull).
d) The plugin »DataRef Editor« (optional, but extremely high recommended).
e) Some skills in programming Lua (FlyWithLua uses LuaJIT, compatible to Lua 5.1).
f) Knowledge about DataRefs.

Page 11 of 129

1.2

Difference between Core, Complete, NG and Source Edition

1

USING THE PLUGIN

1.2 Difference between Core, Complete, NG and Source Edition

FlyWithLua is originally published in three different flavors but only the NG version is currently
supported.
The first version is the Core Edition. This is the right version to start your first steps in using Lua
to customize your X-Plane installation. The Core Edition is fully supported by the FlyWithLua
developer team and acts as the heart of the FlyWithLua economy. If you got an error with
this version, check if you have the latest version installed and report your issue together with a
Log.txt and FlyWithLua_debug.txt file at the official FlyWithLua support forum.
Please ask for support here: HelpMe Forum of FlyWithLua
The second edition was made for the user who know what they are doing. We call it the Complete Edition. The Complete Edition is a ready to use binary version of FlyWithLua with
additional libraries and no restrictions (access to private art control DataRefs is possible
with this version). Remember, Pandora keeps her box widely opened for you in the Complete
Edition, but this has not only positive effects. The more possibilities you get to manipulate XPlane, the more possible frustration may be the result, when Laminar Research updates X-Plane.
If you do not know what the last sentence is about, you should not use the Complete Edition!
This version of FlyWithLua has a lower level of support. Please ask in the same HelpMe Forum
to get some assistance.
The third edition was created to alow FlyWithLua to be used in VR and because of that effort
can also be used on a second monitor. It has all the features of the previous Complete edition so
can access private art control datarefs. The support is by the X-Plane org comunity and can be
found here. Please ask in the same HelpMe Forum to get some assistance.
For the real hackers we have the whole source code of FlyWithLua Core Edition published on
GitHub. Just grab the code and compile it for your own, to have the full control.
You want all menu entries blink in pink? If you are a C/C++ crack, just edit the source and compile your own flavor. FlyWithLua is published with the MIT license, so you can do everything
you want to the source code without getting into trouble with us.
Years of hard work is our free gift to you. Use it with respect and honor.

Page 12 of 129

1.3

Installation

1

USING THE PLUGIN

1.3 Installation

To use the plugin, just copy the complete folder FlyWithLua into X-Plane’s main plugin folder.
The main plugin folder looks like this:
«place where you store the sim»/X-Plane 10/Resources/plugins/1
When the plugin starts up, there must be a folder named
«place where you store the sim»/X-Plane 10/Resources/plugins/FlyWithLua/Scripts/2
with at least one file in it (no matter if it is a Lua script or not). When you copy the complete
folder, you will start with two subfolders, Scripts and Scripts (disabled). All scripts inside
the Scripts folder will be run automatically by the plugin.
When the plugin starts, it will run all files inside the Scripts folder, who end as:
.fwl, .FWL, .lua, .Lua or .LUA
If a file is hidden (it’s name begins with a single dot), the file will be ignored by the plugin.
This means, you have three ways to disable a script.
a) Change the endian.
b) Hide it (let the name start with ».«).
c) Move it to another folder.
I prefer the last way, so you find the folder Scripts (disabled) filled with examples. All
these examples may produce an enormous frustration, if you just copy them into the »active«
folder. They may redefine your joystick setting for example. So be very carefully and modify
them before usage. Lua scripts are a powerful weapon!

1 If you use X-Plane 9 instead of X-Plane 10, search for the README_XP9.txt file and follow the instruction inside.
2 If

you rename the plugin, it will stop working. So never change it’s folder name.

Page 13 of 129

1.4

How to interact with Lua

1

USING THE PLUGIN

1.4 How to interact with Lua

If you have XSquawkBox3 installed, there is an easy way to talk to Lua. If you type in a line
into XSquawkBox starting with a > (a greater than sign), the line is send directly to Lua, instead
of talking to your VATSIM channel (on COM1). Try the following code:
>print(2+3)
If everything is fine, Lua will print a 5 into the XSquawkBox’s main text display4 . The output
produced by Lua is not forwarded to the VATSIM COM1 channel. So don’t be afraid of disturbing the controller. You can check this behavior as XSquawkBox prints all internal information
in dark red color.
So FlyWithLua is a little pocket calculator? Hmm, why not. But this is not the intension of the
plugin. FlyWithLua was made to interact with DataRefs.
1.5 Lua variables and DataRefs

Lua can handle variables. You can try it out:
>LuaIsNice = true
>print(LuaIsNice)
Not very spectacular, but wait, let’s tell Lua to bind a variable to a DataRef:
>DataRef("battery", "sim/cockpit/electrical/battery_on", "writable")
>print(battery)
Wow! Lua prints out a 1 if the battery is on, or a 0 when the battery is off. That’s magic! But it
goes even better. Turn on your plane and type this:
>battery = 0
Plopp – your plane is down. If a variable is connected to a DataRef, and you define the connection as not readonly (the third parameter of the function call was "writable"), all changes on
the variable will be pushed to the DataRef instandly.

3 If

not, you can click on the menu entry »Enter a line of code« in FlyWithLua’s plugin menu. There is no need to
have XSquawkBox installed to use FlyWithLua. On the other hand, flying online on VATSIM is really cool.
4 Use the developer console to see the output, if you don’t have XSquawkBox installed.

Page 14 of 129

1.6

Writing a first config file

1

USING THE PLUGIN

1.6 Writing a first config file

With the knowledge now, we can write a little config script like this:
1
2
3
4
5
6

D a t a R e f ( " p i t c h _ n u l l z o n e " , " sim / j o y s t i c k / j o y s t i c k _ p i t c h _ n u l l z o n e " , " w r i t a b l e " )
pitch_nullzone = 0.0
D a t a R e f ( " r o l l _ n u l l z o n e " , " sim / j o y s t i c k / j o y s t i c k _ r o l l _ n u l l z o n e " , " w r i t a b l e " )
roll_nullzone = 0.0
D a t a R e f ( " h e a d i n g _ n u l l z o n e " , " sim / j o y s t i c k / j o y s t i c k _ h e a d i n g _ n u l l z o n e " , " w r i t a b l e " )
heading_nullzone = 0.0

This works very well, but it is not really user friendly. So I decided to give FlyWithLua some
extra functions, who make the code more cheerful. The config file can be alternatively written
as:
1
2
3

s e t ( " sim / j o y s t i c k / j o y s t i c k _ p i t c h _ n u l l z o n e " ,
0.0 )
s e t ( " sim / j o y s t i c k / j o y s t i c k _ r o l l _ n u l l z o n e " ,
0.0 )
s e t ( " sim / j o y s t i c k / j o y s t i c k _ h e a d i n g _ n u l l z o n e " , 0 . 0 )

Much easier to read, isn’t it?
1.7 Pre-defined variables

But what to code if you want a nullzone of 0.1 in your piston, but 0.0 in your helicopter? You
can use the pre-defined variable PLANE_ICAO.
1
2
3
4
5
6
7
8
9
10
11
12

−− n u l l z o n e o f my l i t t l e C e s s n a
i f ( PLANE_ICAO == " C172 " ) t h e n
s e t ( " sim / j o y s t i c k / j o y s t i c k _ p i t c h _ n u l l z o n e " ,
0.1
s e t ( " sim / j o y s t i c k / j o y s t i c k _ r o l l _ n u l l z o n e " ,
0.1
s e t ( " sim / j o y s t i c k / j o y s t i c k _ h e a d i n g _ n u l l z o n e " , 0 . 1
end
−− n u l l z o n e o f my l i t t l e c o f f e e m i l l
i f ( PLANE_ICAO == " R22 " ) t h e n
s e t ( " sim / j o y s t i c k / j o y s t i c k _ p i t c h _ n u l l z o n e " ,
0.0
s e t ( " sim / j o y s t i c k / j o y s t i c k _ r o l l _ n u l l z o n e " ,
0.0
s e t ( " sim / j o y s t i c k / j o y s t i c k _ h e a d i n g _ n u l l z o n e " , 0 . 0
end

)
)
)

)
)
)

1.8 Loop Callbacks

All your code will be calculated automatically during startup, if you change the plane or position,
or when you click on Reload all Lua script files in the plugin’s main menu.
If this is not enough to you, you can generate code, that will be calculated continuously in a loop
callback.
These two commands given to Lua (using XSquawkBox’s input line) will produce an ugly behavior:

Page 15 of 129

1.9

Menu entries

1

USING THE PLUGIN

>DataRef("poslight", "sim/cockpit/electrical/nav_lights_on", "writable")
>do_sometimes("poslight = 0")
Now, from time to time, Lua will turn off your navigation lights. Try it out to see how it works.
You will not bewitch the simulator for the rest of your life. A simple click on the menu entry
Reload all Lua script files will reset your magic spell.
1.9 Menu entries

Every time you get your little bird back to Paderborn/Lippstadt (EDLP), you want to talk to the
tower controller (on frequency 133.375) to initialize your VFR approach, and want your needle
pointing to PAD (on frequency 354). Maybe you want to tune in the ILS signal.
You can define an ATC menu entry to script it. This will help a lot, because the code will only be
calculated if you click on the menu entry. Nobody always want to fly around Paderborn, right?
Write a little file like this and name it »EDLP_VFR_Approach.lua«.
1
2
3

D a t a R e f ( "COM1" , " sim / c o c k p i t / r a d i o s / c o m 1 _ f r e q _ h z " , " w r i t a b l e " )
D a t a R e f ( "NAV1" , " sim / c o c k p i t / r a d i o s / n a v 1 _ f r e q _ h z " , " w r i t a b l e " )
D a t a R e f ( "ADF1" , " sim / c o c k p i t / r a d i o s / a d f 1 _ f r e q _ h z " , " w r i t a b l e " )

4
5
6
7
8

add_ATC_macro ( " coming home " , [ [−− f l y home t o EDLP
COM1 = 13337
NAV1 = 10855
ADF1 = 3 5 4 ] ] )

As the code of your macro needs more than one line, you use the double brackets [[ and ]] to
write down a multi line string as the second argument of the function add_ATC_macro. So don’t
forget the closing normal bracket, as shown in the last line above.
1.10 Menu switches

If you want to toggle a special behavior of your simulator, defined in a script, but you do not
want to rename or move the file and reload all scripts to use it or not, you can use menu entry
switches.
It’s just as easy as giving Lua’s add_macro function two additional string parameters. Write a
file like this and name it »transponder_helper.lua«.
If you don’t want to copy&paste the code, just take a look into the Scripts (disabled)
folder.
1
2
3
4
5
6

−− The g r o u n d s p e e d i s i n m / s ( m e t e r p e r s e c o n d ) , n o t kn ( k n o t s ) , and a l w a y s r e a d o n l y
D a t a R e f ( " g r o u n d s p e e d " , " sim / f l i g h t m o d e l / p o s i t i o n / g r o u n d s p e e d " )
−− The t r a n s p o n d e r c o d e i s a 4− d i g i t i n t e g e r
D a t a R e f ( " t r a n s p o n d e r _ c o d e " , " sim / c o c k p i t / r a d i o s / t r a n s p o n d e r _ c o d e " , " w r i t a b l e " )
−− T r a n s p o n d e r mode ( o f f =0 , s t d b y =1 , on =2 , t e s t =3)
D a t a R e f ( " t r a n s p o n d e r _ m o d e " , " sim / c o c k p i t / r a d i o s / t r a n s p o n d e r _ m o d e " , " w r i t a b l e " )

7
8

−− we s t a r t i n Europe m o s t o f t h e t i m e

Page 16 of 129

1.10

9

Menu switches

1

USING THE PLUGIN

t r a n s p o n d e r _ c o d e = 7000

10
11
12
13
14
15
16
17
18
19
20
21
22
23

−− t u r n on y o u r t r a n s p o n d e r when f l y i n g f a s t e r t h a n 20 m / s ( a b o u t 40 kn )
function check_transponder ()
i f ( t r a n s p o n d e r _ h e l p == t r u e ) t h e n
i f ( ( g r o u n d s p e e d > 2 0 ) and ( t r a n s p o n d e r _ m o d e ~= 2 ) ) t h e n
transponder_mode = 2
XPLMSpeakString ( " T r a n s p o n d e r s e t t o a c t i v e " )
end
i f ( ( g r o u n d s p e e d < 2 0 ) and ( t r a n s p o n d e r _ m o d e > 1 ) ) t h e n
transponder_mode = 1
XPLMSpeakString ( " T r a n s p o n d e r s e t t o s t a n d b y " )
end
end
end

24
25
26

−− c h e c k i t e v e r y 10 s e c
do_sometimes ( " c h e c k _ t r a n s p o n d e r ( ) " )

27
28
29

−− make a s w i t c h a b l e menu e n t r y , d e f a u l t i s on
add_macro ( " A u t o m a t i c a l l y s e t T r a n s p o n d e r " , " t r a n s p o n d e r _ h e l p = t r u e " , " t r a n s p o n d e r _ h e l p
= false " , " activate ")

Page 17 of 129

2

REFERENCE

2 Reference
2.1 Predefined variables

All predefined variables are readonly. If you change them, X-Plane will not recognize it.
2.1.1 LONGITUDE

Gives the actual longitude value in decimal as a double float value (remember Lua didn’t know
float but only number). As X-Plane uses the data type double, but the numbers in Lua are only
float, you will get an approximation.
The value is readonly, like all predefined variables. So it isn’t possible to replace the plane in
it’s position by changing the value.
Positive values in LONGITUDE are east, negative values are west.
2.1.2 LATITUDE

This gives the latitude value of the plane’s position as a decimal value. So for example seven
degree thirty minutes north is represented as 7.5 (a positive value, negative values are south).
2.1.3 PLANE_ICAO

A string holding the plane’s ICAO code in it.
2.1.4 PLANE_TAILNUMBER

The Tailnumber of the plane as a string.
2.1.5 SCREEN_WIDTH

The screen width in pixel.
2.1.6 SCREEN_HIGHT

The screen hight in pixel.

Page 18 of 129

2.1

Predefined variables

2

REFERENCE

2.1.7 MOUSE_X

Horizontally position of the mouse pointer. Coordinates start on the left side with 0 (zero).
2.1.8 MOUSE_Y

Vertically position of the mouse pointer. Coordinates start on the bottom side with 0 (zero).
2.1.9 XSB_METAR

A string containing the last metar received by XSquawkBox. If you are not connected to VATSIM, the variable will be useless. It is readonly.
Readonly means, you can’t modify the online weather by changing the XSB_METAR variable!
2.1.10 LUA_RUN

An integer value showing how often Lua was (re)started. During the very first run of Lua, it’s
value is 1. You can use it to do things only once after X-Plane was started, and do not repeat
when a new plane was loaded or the airport was changed. (Both will force a Lua restart.)
2.1.11 XPLANE_VERSION

An integer value showing the version number of X-Plane. FlyWithLua is designed to run on
X-Plane version 10.x, but it may run on X-Plane 9. To check if you are really on X-Plane 10 (or
newer), you can say: if XPLANE_VERSION > 1000 then ... end.
Example given: the version X-Plane 10.10rc3 shows: XPLANE_VERSION = 10101
2.1.12 XPLANE_HOSTID

An integer value showing the HostID of X-Plane, an OS-specific value (totally unnecessary).
2.1.13 SDK_VERSION

An integer value showing the version number of the SDK, FlyWithLua is running on. The SDK
version should be 210 or above for X-Plane 10. If not, download a version for X-Plane 10 of
FlyWithLua.

Page 19 of 129

2.1

Predefined variables

2

REFERENCE

2.1.14 SYSTEM

A string telling you on witch computer system FlyWithLua (the simulator) is running. It’s
value is "IBM" on Windows systems, "APL" on Apple Macintosh systems and "LIN" on Linux
systems.
2.1.15 SYSTEM_ARCHITECTURE

A number either 32 or 64, depending on the architecture. 64 means X-Plane is running in 64-bit,
32 means the simulator and all plugins are running in 32-bit.
2.1.16 XPLANE_LANGUAGE

A string value showing the language of X-Plane’s menus. The value can be "English", "French",
"German", "Italian", "Spanish", "Korean", "Russian", "Greek", "Japanese", "Chinese"
or "Unknown".

Page 20 of 129

2.1

Predefined variables

2

REFERENCE

Since FlyWithLua version 2.0 all menu entries are no longer forced to English. To create a
multiple language support for your plugin, write code like this5 :
1

d a t a r e f ( "COM1" , " sim / c o c k p i t / r a d i o s / c o m 1 _ f r e q _ h z " , " w r i t a b l e " )

2
3
4

i f XPLANE_LANGUAGE == " German " t h e n
add_macro ( " S t e l l e d a s FunkgerÃd’t a u f UNICOM" , "COM1 = 12280 " )

5
6
7

e l s e i f XPLANE_LANGUAGE == " F r e n c h " t h e n
add_macro ( " FrÃl’quence r a d i o p o i n t s u r l ’UNICOM" , "COM1 = 12280 " )

8
9
10

e l s e i f XPLANE_LANGUAGE == " S p a n i s h " t h e n
add_macro ( " P u n t o de f r e c u e n c i a de r a d i o en l a UNICOM" , "COM1 = 12280 " )

11
12
13

e l s e i f XPLANE_LANGUAGE == " I t a l i a n " t h e n
add_macro ( " P u n t o d i f r e q u e n z a r a d i o s u l l a UNICOM" , "COM1 = 12280 " )

14
15
16
17

else
add_macro ( " S e t r a d i o t o UNICOM" , "COM1 = 12280 " )
end

2.1.17 DIRECTORY_SEPARATOR

A string containing the directory separator of the current OS.
2.1.18 SYSTEM_DIRECTORY

The complete OS-specific path to the X-Plane root directory with trailing slash.
2.1.19 SCRIPT_DIRECTORY

The complete OS-specific path to the scripts including a directory separator as it’s last character.
If you want to write a file named my_info.txt into the scripts directory (instead of X-Plane’s
main directory), use code like this:
infofile = os.open(SCRIPT_DIRECTORY .. "my_info.txt", "w")

2.1.20 INTERNALS_DIRECTORY

The complete OS-specific path to the FlyWithLua Internals directory with trailing slash.
2.1.21 MODULES_DIRECTORY

The complete OS-specific path to the FlyWithLua Modules directory with trailing slash.
5 All

text other than English or German was translated using Google Translator.

Page 21 of 129

2.1

Predefined variables

2

REFERENCE

2.1.22 AIRCRAFT_PATH

The full path to your aircraft file, ending with a directory separator.
2.1.23 AIRCRAFT_FILENAME

The name of the ACF aircraft file, including the endian ".acf".
2.1.24 DO_EVERY_FRAME_TIME_SEC

The duration time in seconds of the every frame loop.
2.1.25 DO_EVERY_DRAW_TIME_SEC

The duration time in seconds of the drawing loop.
2.1.26 DO_SOMETIMES_TIME_SEC

The duration time in seconds of the loop to be executed sometimes.
2.1.27 DO_OFTEN_TIME_SEC

The duration time in seconds of the often executed loop.
2.1.28 SCRIPTS_LOADING_TIME_SEC

The time it takes to load all scripts.
2.1.29 CLOCKS_PER_SEC

The number of clock ticks in one second, a C value depending on your system.
1
CLOCKS_PER_SEC

is the ninimal time that can be maesured.

2.1.30 LUA_MEMORY_USAGE_KB

The memory usage of the Lua environment in kB. This is not the complete memory consumption
of your scripts, as some objects like wave files are not stored into Lua, but are allocated in C by
the plugin FlyWithLua.

Page 22 of 129

2.2

Lua functions

2

REFERENCE

2.2 Lua functions

The following functions are written in core C++ and are a part of the plugin. Most of them are
multi-defined to handle different count of arguments.
2.2.1 DataRef( "variable name", "DataRef name" )

a) variable name = Name of the Lua variable representing the DataRef.
b) DataRef name = Name of the DataRef. Look at the listing of all DataRefs.
Binds a Lua variable to a DataRef6 . The connection will be forced to readonly. Not possible to
array DataRefs.
2.2.2 DataRef( "variable name", "DataRef name", "readonly" )

a) variable name = Name of the Lua variable representing the DataRef.
b) DataRef name = Name of the DataRef. Look at the listing of all DataRefs.
c) readonly = Should the variable be pushed to X-Plane when it is changed? Say "readonly"
to have it readonly or "writable" to make it writable.
Binds a Lua variable to a DataRef. The connection will be writealbe if you say "writable" as
the third argument and if the DataRef is writable. Not possible to array DataRefs.
2.2.3 DataRef( "variable name", "DataRef name", "readonly", index )

a) variable name = Name of the Lua variable representing the DataRef.
b) DataRef name = Name of the DataRef. Look at the listing of all DataRefs.
c) readonly = Should the variable be pushed to X-Plane when it is changed? Say "readonly"
to have it readonly or "writable" to make it writable.
d) index = The index of an array DataRef.
Binds a Lua variable to a DataRef. The connection will be writalbe if you say "writable" as
the third argument and if the DataRef is writable. For array DataRefs use a fourth argument, the
index starting at 0 (Zero). It will bind the element at the given index. It will not bind an array as
a Lua table.

6 You

can spell it dataref() instead of DataRef(), if you don’t like uppercase letters.

Page 23 of 129

2.2

Lua functions

2

REFERENCE

2.2.4 table = dataref_table( "DataRef name")

a) table = Name of the Lua variable representing the DataRef. The variable will be a Lua
table, access it like an anrray with index starting at 0 (Zero).
b) DataRef name = Name of the DataRef. Look at the listing of all DataRefs.
This function will create a table variable to access a DataRef. You can use it for any type of
DataRef, no matter if the DataRef is an array or not. Here are some examples:
1
2

−− t h e b a t t e r y D a t a R e f i s an a r r a y o f up t o 8 b a t t e r y s w i t c h e s
b a t t e r y = d a t a r e f _ t a b l e ( " sim / c o c k p i t 2 / e l e c t r i c a l / b a t t e r y _ o n " )

3
4
5

−− now we t u r n on t h e f i r s t
battery [0] = 1

b a t t e r y of the plane

6
7
8

−− b u t i t w i l l work on non−a r r a y D a t a R e f s t o o
COM1FREQ = d a t a r e f _ t a b l e ( " sim / c o c k p i t / r a d i o s / c o m 1 _ f r e q _ h z " )

9
10
11

−− s w i t c h i t t o UNICOM
COM1FREQ[ 0 ] = 12280

2.2.5 define_shared_DataRef("DataRef name", "DataRef type")

a) DataRef name = Name of the DataRef. Look at the listing of all DataRefs.
b) DataRef type = Type of the DataRef. This type is a string argument and can be
"Int", "Float", "IntArray", "FloatArray", "Double" or "Data".
With this function you will create a DataRef of the given type if it does not exist. If it exist
and the type is different, you will get an error message. If it still exists with the same type, this
command will do nothing. Shared DataRefs should help you interacting with other plugins.
2.2.6 table = create_dataref_table( "DataRef name", "DataRef type")

a) table = Name of the Lua variable representing the DataRef. The variable will be a Lua
table, access it like an anrray with index starting at 0 (Zero).
b) DataRef name = Name of the DataRef. Look at the listing of all DataRefs.
c) DataRef type = Type of the DataRef. This type is a string argument and can be
"Int", "Float", "IntArray", "FloatArray", "Double" or "Data".
Here you have the best way to create a new DataRef and connect it to a table variable inside
Lua.
This is an example:

Page 24 of 129

2.2

1
2

Lua functions

2

REFERENCE

−− A s t r i n g m u s t be c r e a t e d a s a " Data " t y p e
m y _ w e l c o m e _ s t r i n g = c r e a t e _ d a t a r e f _ t a b l e ( " F l y W i t h L u a / u s e l e s s _ s a m p l e s / welcome " , " D a t a " )

3
4
5

−− no m a t t e r i f i t l o o k s l i k e a t a b l e , j u s t i n d e x t h e f i r s t e l e m e n t t o f i l l
m y _ w e l c o m e _ s t r i n g [ 0 ] = " H e l l o World ! "

it

6
7
8
9

−− a n o t h e r example , now we c r e a t e an i n t e g e r v a l u e
th e_ an sw er = c r e a t e _ d a t a r e f _ t a b l e ( " FlyWithLua / u s e l e s s _ s a m p l e s / t he _a ns we r " , " I n t " )
t h e _ a n s w e r [ 0 ] = 42

10
11
12
13
14

−− i n t i m e s
all_answers
all_answers
all_answers

of
=
[0]
[1]

a l t e r n a t i v e f a c t s , we can h a v e m u l t i p l e a n s w e r s
c r e a t e _ d a t a r e f _ t a b l e ( " FlyWithLua / u s e l e s s _ s a m p l e s / answers " , " I n t A r r a y " )
= 42
= 2017

2.2.7 DataRef name, Index, readonly, DataRef type, DataRef ID = get_DataRef_binding(
"variable name" )

a) variable name = Name of the Lua variable representing the DataRef.
b) DataRef name = Name of the DataRef. Look at the listing of all DataRefs.
c) Index = The Index of the DataRef. This is always 0 (zero) if the DataRef isn’t an array.
d) readonly = This results to true is the DataRef is readonly and false if it’s writable.
e) DataRef type = Type of the DataRef. 1 = integer, 2 = float, 4 = double, 8 = float array,
16 = integer array and 32 = data (strings).
f) DataRef ID = The ID of the DataRef. A pointer to the memory, the DataRef is stored.
2.2.8 button( button number )

a) button number = Number of the button, starting at 0 (zero).
Returns the value of the actual state of a joystick button. button(i) will result in true if the
button is pressed, else it gives back false. The argument i must be an integer, ranging from 0
to 1599. Check out the number in X-Plane’s advanced buttons menu.
2.2.9 last_button( button number )

a) button number = Number of the button, starting at 0 (zero).

Page 25 of 129

2.2

Lua functions

2

REFERENCE

Returns the value of the state of a joystick button, as it was during the last frame. last_button(i)
will result in true if the button was pressed, else it gives back false. The argument i must be an
integer, ranging from 0 to 1599. Check out the number in X-Plane’s advanced buttons menu.
Advice:
Always use button() and last_button() to grab joystick values, instead of using
DataRef("MyButton", "sim/joystick/joystick_button_values", "readonly", 123),
if you like super fast code execution. The functions button() and last_button() deliver
values much efficient than user defined DataRefs.
2.2.10 create_switch( button number, DataRef name, index, off value, on value )

a) button number = Number of the button, starting at 0 (zero).
b) DataRef name = Name of the DataRef. Look at the listing of all DataRefs.
c) index = The index of an array DataRef, else 0.
d) off value = Value to be set when button is not pressed (off).
e) on value = Value to be set when button is pressed (on).
This will turn a joystick buton into a switch controlling a DataRef. If the button is not pressed,
the DataRef will be set to the off value, else to the on value. The index is 0 (zero) for non-array
DataRefs.
The last three arguments are optional. If you leave them away, Lua will guess 0 for the index and
the off value and 1 for the on value. So this will be fine to let button no. 15 control the battery
as a real hardware switch:
>create_switch(15, "sim/cockpit/electrical/battery_on")

2.2.11 create_positive_edge_flip( button number, DataRef name, index, first value,
second value )

a) button number = Number of the button, starting at 0 (zero).
b) DataRef name = Name of the DataRef. Look at the listing of all DataRefs.
c) index = The index of an array DataRef, else 0.
d) first value = Value to be set when button is just pressed (positive edge detecttion).
e) second value = Value to be set when button is just pressed but the DataRef’s value is equal
to the first value.

Page 26 of 129

2.2

Lua functions

2

REFERENCE

This is similar to the create_switch() function, but it will flip between the two values, given
as the last two arguments, every time a positive edge was detected (when the button is pressed
just in that moment).
The last three arguments are optional. If you leave them away, Lua will guess 0 for the index
and the first value and 1 for the second value. So this will be fine to let button no. 15 control the
battery and flip it every time it is pressed:
>create_positive_edge_flip(15, "sim/cockpit/electrical/battery_on")
Lua will automatically handle it like this:
>create_positive_edge_flip(15, "sim/cockpit/electrical/battery_on", 0, 0, 1)

2.2.12 create_negative_edge_flip( button number, DataRef name, index, first value,
second value )

a) button number = Number of the button, starting at 0 (zero).
b) DataRef name = Name of the DataRef. Look at the listing of all DataRefs.
c) index = The index of an array DataRef, else 0.
d) first value = Value to be set when button is just released (positive edge detecttion).
e) second value = Value to be set when button is just released but the DataRef’s value is
equal to the first value.
Nearly the same as the function create_positive_edge_flip(), but it will react when the
button is released. For an engeneer, this is the negative edge of the button’s signal.
2.2.13 create_positive_edge_trigger( button number, DataRef name, index, value )

a) button number = Number of the button, starting at 0 (zero).
b) DataRef name = Name of the DataRef. Look at the listing of all DataRefs.
c) index = The index of an array DataRef, else 0.
d) value = Value to be set in the moment when button is pressed down (positive signal edge).
This will set the DataRef to the given value in the moment, when the button is pressed down,
not during hold. In engineer’s words it’s a positive edge detection.

Page 27 of 129

2.2

Lua functions

2

REFERENCE

2.2.14 create_negative_edge_trigger( button number, DataRef name, index, value )

a) button number = Number of the button, starting at 0 (zero).
b) DataRef name = Name of the DataRef. Look at the listing of all DataRefs.
c) index = The index of an array DataRef, else 0.
d) value = Value to be set in the moment when button is released (negative signal edge).
This will set the DataRef to the given value in the moment, when the button is released. In
engineer’s words it’s a negative edge detection.
2.2.15 create_positive_edge_increment( button number, DataRef name, index, stepping,
limit, rounding )

a) button number = Number of the button, starting at 0 (zero).
b) DataRef name = Name of the DataRef. Look at the listing of all DataRefs.
c) index = The index of an array DataRef, else 0.
d) stepping = Value to be added to the DataRef when the button is pressed down (positive
signal edge).
e) limit = Value that should not be trespass.
f) rounding = Value must be a power of ten, the DataRef should be rounded to.
This will increase the DataRef by the given step when the button is pressed down.
The parameter rounding is optional. If you give this value to Lua, the DataRef will be rounded.
Here is an example:
>create_positive_edge_increment(13, "sim/flightmodel/engine/ENGN_cowl", 2, 0.1, 1.0, 0.1)
This will increase the cowl flap of engine no. 3 (X-Plane starts numbering at 0) by 0.1 up to the
limit of 1.0 – and the result will be rounded to one decimal place. Rounding is only possible to
float DataRefs.
2.2.16 create_negative_edge_increment( button number, DataRef name, index, stepping,
limit, rounding )

The same as before, but with negative edge detection (works when the button is released).

Page 28 of 129

2.2

Lua functions

2

REFERENCE

2.2.17 create_positive_edge_decrement( button number, DataRef name, index, stepping,
limit, rounding )

Same as before, but decreases the DataRef.
An other example (the radio frequency is an integer DataRef):
>create_positive_edge_increment(15, "sim/cockpit/radios/com1_freq_hz", 0, 100, 13797)
>create_positive_edge_decrement(14, "sim/cockpit/radios/com1_freq_hz", 0, 100, 11800)

2.2.18 create_negative_edge_decrement( button number, DataRef name, index, stepping,
limit, rounding )

What the hell could this does? ;)
2.2.19 create_axis_median( axis number, variable name )

a) axis number = Number of the axis, starting at 0 (zero).
b) variable name = Name of the variable to be filled with the median value of the axis.
Calculates a median value of the last five values from an axis and puts it into a Lua variable. This
is an example how to store the median value of axis no. 3 (the fourth axis shown in X-Plane, as
we start counting with zero) into the variable median_throttle:
>create_axis_median(3, "median_throttle")

2.2.20 get( "DataRef name" )

a) DataRef name = Name of the DataRef. Look at the listing of all DataRefs.
Pulling a DataRef to Lua. This function returns one value pulled from the DataRef. Slower than
the automatic pull, but does not need a variable. Good for initial scripts or macros. Highly not
recommended in callbacks. This is the version used for non array DataRefs. If you try to pull an
array DataRef with this function, you will get the first element of the array.
An easy way of reading out a DataRef with the XSquawkBox’s input line. Check DataRefs like
this:
>print(get("sim/aircraft/weight/acf_m_fuel_tot"))

Page 29 of 129

2.2

Lua functions

2

REFERENCE

2.2.21 get( "DataRef name", index )

a) DataRef name = Name of the DataRef. Look at the listing of all DataRefs.
b) index = The index of an array DataRef.
Pulling a DataRef to Lua. This function returns one value pulled from the DataRef. Slower than
the automatic pull, but does not need a variable. Good for initial scripts or macros. Highly not
recommended in callbacks. This is the version used for array DataRefs.

Page 30 of 129

2.2

Lua functions

2

REFERENCE

2.2.22 set( "DataRef name", value )

a) DataRef name = Name of the DataRef. Look at the listing of all DataRefs.
b) value = The value you want to push to the DataRef.
Pushing a given value to a DataRef. Not possible for array or string DataRefs. The set function
is slower than the automatic pushing of variables to DataRefs. But on the other hand it will not
create a global variable. This can provide getting in confict between multiple scripts using the
same variable for different DataRefs, a situation normally crashing the system.
Use the set function to fill DataRefs during startup (typically config files) or in macros, when
you only need to push the values (and do not need to pull them into Lua variables).
2.2.23 set_array( "DataRef name", index, value )

a) DataRef name = Name of the DataRef. Look at the listing of all DataRefs.
b) index = The index of an array DataRef.
c) value = The value you want to push to the DataRef.
Does the same as the set() function, but to be used for array DataRefs.
2.2.24 set_button_assignment( button number, "simulator function")

a) button number = Number of the button (starting with 0).
b) simulator function = Name of the function you want to assign. You can copy&paste the
name from X-Plane’s advanced button setting menu. Must be a string, don’t forget the
brackets.
Assigning a function given by X-Plane to a joystick button. The same as clicking it inside
the advanced button settings menu. Usefull to make different configs for different planes or
situations.

Page 31 of 129

2.2

Lua functions

2

REFERENCE

2.2.25 set_axis_assignment( axis number, "axis function", "reverse")

a) axis number = Number of the axis (starting with 0). Since X-Plane 10.10 Austin forces
you to guess the numbers or to view inside the config files. Counting them inside the menu
is no longer possible. Please ask him why he did it, not me.
b) axis function = Name of the function you want to assign. You can copy&paste the name
from X-Plane’s advanced button setting menu. Must be a string, don’t forget the brackets.
c) reverse = a string telling X-Plane to reverse the axis if the value is "reverse" or to set a
normal axis if the value is "normal".
Assigning axis functions. Possible values for the function names are: "none", "pitch", "roll",
"yaw", "throttle", "collective", "left toe brake", , "right toe brake", "prop",
"mixture", "carb heat", "flaps", "thrust vector", "wing sweep", "speedbrakes", "displacement",
"reverse", "elev trim", "ailn trim", "rudd trim", "throttle 1", "throttle 2", "throttle 3",
"throttle 4", "prop 1", "prop 2", "prop 3", "prop 4", "mixture 1", "mixture 2",
"mixture 3", "mixture 4", "reverse 1", "reverse 2", "reverse 3", "reverse 4", "landing gear",
"nosewheel tiller", "backup throttle", "cowl flaps", "view left/right", "view up/down",
"view zoom", "camera left/right", "camera up/down", "camera zoom", "gun/bomb left/right",
"gun/bomb up/down", "VR Touchpad X", "VR Touchpad Y" and "VR Trigger".
2.2.26 clear_all_axis_assignments()

Sets all assignments to "none".
2.2.27 clear_all_button_assignments()

Sets all assignments to "sim/none/none".
2.2.28 set_pilots_head( x, y, z, heading, pitch )

a) x, y, z = Position of pilot’s head relative to the plane.
b) heading = The heading of pilot’s head.
c) pitch = The pitch of pilot’s head.
This will set the pilot’s head in position and angle. If we are not in 3D view, 3D view will be
set.

Page 32 of 129

2.2

Lua functions

2

REFERENCE

2.2.29 x, y, z, heading, pitch = get_pilots_head( )

a) x, y, z = Position of pilot’s head relative to the plane.
b) heading = The heading of pilot’s head.
c) pitch = The pitch of pilot’s head.
This will get the pilot’s head position and angle.
2.2.30 command_begin( "simulator function" )

a) simulator function = Name of the function you want to assign. You can copy&paste the
name from X-Plane’s advanced button setting menu.
Execute a simulator given command only one time.
This will execute the "begin" part of a command. X-Plane’s commands have three phases. What
really will happen when you execute one of this parts depends on the original programming
made by Laminar Research (or other). In some cases you will have to experiment the right
command call (the right phase).
2.2.31 command_once( "simulator function" )

a) simulator function = Name of the function you want to assign. You can copy&paste the
name from X-Plane’s advanced button setting menu.
Execute a simulator given command only one time.
This will execute the "main" part of a command. X-Plane’s commands have three phases. What
really will happen when you execute one of this parts depends on the original programming
made by Laminar Research (or other). In some cases you will have to experiment the right
command call (the right phase).
In nearly 100% this is the phase you want to call.
2.2.32 command_end( "simulator function" )

a) simulator function = Name of the function you want to assign. You can copy&paste the
name from X-Plane’s advanced button setting menu.

Page 33 of 129

2.2

Lua functions

2

REFERENCE

Execute a simulator given command only one time.
This will execute the "end" part of a command. X-Plane’s commands have three phases. What
really will happen when you execute one of this parts depends on the original programming
made by Laminar Research (or other). In some cases you will have to experiment the right
command call (the right phase).
2.2.33 logMsg( "string" )

a) string = What you want to say.
Write a string into the Log.txt file in X-Plane’s main directory. You can take a look into the log
file by assigning a button to the simulator function "sim/operation/dev_console". Or you
choose the viewing toggle from the specials menu.
2.2.34 XSBSpeakString( "string" )

a) string = What you want to say.
Write a string into the XSquawkBox. The string will not be send to other pilots or controllers
when connected to VATSIM. Only to give you an easy way to print notes on the screen.
2.2.35 XPLMSpeakString( "string" )

a) string = What you want to say.
Write a string onto the screen for a few seconds and speaks the string if text-to-speak is enabled.
This function will return immediately, the string will be spoken asynchronously. If you fire up
multiple strings at once, you will get a confusing mix. So take care of timing.

Page 34 of 129

2.2

Lua functions

2

REFERENCE

2.2.36 print( "string" )

a) string = What you want to say.
Similar to XSBSpeakString(), but uses it’s own box to display. All text will be displayed for 5
seconds, then the box fades away. To display the box again, you can move the mouse pointer to
the top of the screen. To scroll through the lines, just move the mouse pointer left or right.
2.2.37 do_sometimes( "Lua code string" )

a) Lua code string = A string containing Lua code you want to be calculated every 10 sec.
Calculates a string of Lua code from time to time.
2.2.38 do_often( "Lua code string" )

a) Lua code string = A string containing Lua code you want to be calculated every sec.
Calculates a string of Lua code very often.
2.2.39 do_every_frame( "Lua code string" )

a) Lua code string = A string containing Lua code you want to be calculated every single
frame.
Calculates a string of Lua code every single frame. Can slow down the simulator at a glance.
Use this function carefully!
2.2.40 do_every_draw( "Lua code string" )

a) Lua code string = A string containing Lua code you want to be calculated every single
draw.
Calculates a string of Lua code every single draw. Seems to be the same as do_every_frame(),
but it is different. Only in this drawing callback you are able to draw things like colored text. To
save CPU time, the automatic DataRefs to variables transfer is disabled during a draw callback.
So do not read or write DataRefs, use it only to draw your messages.
Can slow down the simulator at a glance. Use this function carefully!

Page 35 of 129

2.2

Lua functions

2

REFERENCE

2.2.41 do_on_keystroke( "Lua code string" )

a) Lua code string = A string containing Lua code you want to be calculated every time when
the user presses or releases a key.
When the user (pilot) presses or releases a key, a keystroke event starts your Lua code given by
this function. Lua provides these special variables, the last one is writable:
a) VKEY = An integer value representing the key you pressed. Play around with this value a
little bit, it is not the ASCII value.
b) CKEY = The key as a char (string with a single letter).
c) SHIFT_KEY = A boolean value, representing the state of the shift key. If a shift key is
pressed, the value is true, else false.
d) OPTION_KEY = A boolean value, representing the state of the option or alt key. If an
option or alt key is pressed, the value is true, else false.
e) CONTROL_KEY = A boolean value, representing the state of the control key. If a control
key is pressed, the value is true, else false.
f) KEY_ACTION = A string either resulting in "pressed" or "released", depending on
the user action.
g) RESUME_KEY = A boolean value. If it is set to true your script will resume the keystroke
and X-Plane will not recognize it. Default value is false, to not disturb X-Plane or other
plugins.
2.2.42 do_on_mouse_wheel( "Lua code string" )

a) Lua code string = A string containing Lua code you want to be calculated every time when
the user presses, holds down or releases the primary mouse button.
When the user (pilot) moves a mouse wheel, an event handler starts your Lua code given by this
function. Lua provides these special variables, the last one is writable:
a) MOUSE_WHEEL_NUMBER = An positive integer value starting with 0 (zero), indicating
what wheel causes the event. Some operating systems allow more than one mouse wheel.
If not, it will be always 0.
b) MOUSE_WHEEL_CLICKS = An integer value indicating the number of steps the user
moved the wheel. Can be positive or negative depending on the moving direction.
c) RESUME_MOUSE_WHEEL = A boolean value. If it is set to true your script will resume
the mouse wheel movement and X-Plane will not recognize it. Default value is false, to
not disturb X-Plane or other plugins.

Page 36 of 129

2.2

Lua functions

2

REFERENCE

2.2.43 do_on_mouse_click( "Lua code string" )

a) Lua code string = A string containing Lua code you want to be calculated every time when
the user presses, holds down or releases the primary mouse button.
When the user (pilot) presses, holds or releases the primary mouse button, an event handler
starts your Lua code given by this function. Lua provides these special variables, the last one is
writable:
a) MOUSE_STATUS = A string either "down", "drag" or "up". "down" says, the user
just starts pressing the button, "drag" means, he holds down the mouse button and if he
releases the button, you get "up".
b) RESUME_MOUSE_CLICK = A boolean value. If it is set to true your script will resume
the mouse click and X-Plane will not recognize it. Default value is false, to not disturb
X-Plane or other plugins.
2.2.44 do_on_new_metar( "Lua code string" )

a) Lua code string = A string containing Lua code you want to be calculated every time when
the plugin receives a new METAR from XSquawkBox.
This is called by a XSquawkBox event. You can read out the predefined variable XSB_METAR, or
do whatever you like when XSquawkBox sends a new METAR (changes the weather).
2.2.45 do_on_new_XSB_text( "Lua code string" )

a) Lua code string = A string containing Lua code you want to be calculated every time when
the plugin receives a new text message from XSquawkBox.
This is called by a XSquawkBox event. You can read out the predefined variable XSB_TEXT_MESSAGE,
XSB_TEXT_FROM, XSB_TEXT_FREQ, XSB_TEXT_USE, or do whatever you like when XSquawkBox
receives a new text message.
The variable XSB_TEXT_USE can be 0 or 1. If XSB_TEXT_USE is 0 (zero), XSquawkBox will not
display or evaluate the message. Only this variable is pushed back to the XSquawkBox. The
other three variables are read only (pulled from the XSquawkBox before executing the Lua code
string, but not pushed back when finished).
Please keep in mind that the code is executed during the event call (inter plugin communication). So you can not write into a variable defined by the DataRef() function. But the
dataref_table() function works (you can use the variables created this way to write to XPlane).
There is an example script delivered with FlyWithLua. As you can see, the XSB_TEXT_FREQ
contains an integer value representing the frequency in 10 Hz multiplied by the value.

Page 37 of 129

2.2

Lua functions

2

REFERENCE

2.2.46 do_on_exit( "Lua code string" )

a) Lua code string = A string containing Lua code you want to be executed when Lua stops.
The will be executed only on normal stops, like changing the airport or aircraft or shutting
down X-Plane. The code can/will not be execuded on errors.
Use this function to collect code that is executed when Lua stops working because of a script
reload. This is not for error handling, but can be usefull if you want to store values to disk for
the next time you start Lua.
2.2.47 draw_string( x, y, "string" )

a) x = Horizontally position where you want to draw. Starts on the left side from 0 (Zero).
b) y = Vertically position where you want to draw. Starts from the bottom with value 0 (Zero).
c) string = The string you want to see on top of the screen.
Prints a string onto the screen. Will only work during draw callbacks. The color is set to white.
The drawing system is for advanced users only!
2.2.48 draw_string( x, y, "string", "color" )

a) x = Horizontally position where you want to draw. Starts on the left side from 0 (Zero).
b) y = Vertically position where you want to draw. Starts from the bottom with value 0 (Zero).
c) string = The string you want to see on top of the screen.
d) color = A string describing the color you want to choose.
Prints a string onto the screen. Will only work during draw callbacks. The color can be "white",
"black", "grey", "red", "green", "blue", "yellow", "magenta" or "cyan".
The drawing system is for advanced users only!

Page 38 of 129

2.2

Lua functions

2

REFERENCE

2.2.49 draw_string( x, y, "string", red, green, blue )

a) x = Horizontally position where you want to draw. Starts on the left side from 0 (Zero).
b) y = Vertically position where you want to draw. Starts from the bottom with value 0 (Zero).
c) string = The string you want to see on top of the screen.
d) red = A float value from 0.0 to 1.0 choosing the red part of a RGB color.
e) green = A float value from 0.0 to 1.0 choosing the green part of a RGB color.
f) blue = A float value from 0.0 to 1.0 choosing the blue part of a RGB color.
If the predefined color don’t fit your needs, choose a custom RGB value.
The drawing system is for advanced users only!
2.2.50 draw_string_Helvetica_10( x, y, "string" )

a) x = Horizontally position where you want to draw. Starts on the left side from 0 (Zero).
b) y = Vertically position where you want to draw. Starts from the bottom with value 0 (Zero).
c) string = The string you want to see on top of the screen.
Prints a string onto the screen. Will only work during draw callbacks.
This will print the text to screen using the GLUT library instead of the X-Plane SDK. So you
will have to set the color first by glColor4f(red, green, blue, alpha). It will print the
text using the bitmap font GLUT_BITMAP_HELVETICA_10.
2.2.51 draw_string_Helvetica_12( x, y, "string" )

The same as above, but using the bitmap font GLUT_BITMAP_HELVETICA_12.
2.2.52 draw_string_Helvetica_18( x, y, "string" )

The same as above, but using the bitmap font GLUT_BITMAP_HELVETICA_18.
2.2.53 draw_string_Times_Roman_10( x, y, "string" )

The same as above, but using the bitmap font GLUT_BITMAP_TIMES_ROMAN_10.

Page 39 of 129

2.2

Lua functions

2

REFERENCE

2.2.54 draw_string_Times_Roman_24( x, y, "string" )

The same as above, but using the bitmap font GLUT_BITMAP_TIMES_ROMAN_24.
2.2.55 measure_string( "string" )

a) string = The string you want to measure.
Returns the length of a given string in screen pixel as a float number. Calculation is based on the
standard proportional font used by draw_string().
2.2.56 measure_string( "string", "font name" )

a) string = The string you want to measure.
b) font name = The name of the font for use with GLUT.
Returns the length of a given string in screen pixel as an integer number. Calculation is based on
the font given by the second argument. It can be Helvetica_10, Helvetica_12, Helvetica_18,
Times_Roman_10 or Times_Roman_24.
2.2.57 hight, width = bubble( x, y, "title", . . . )

a) x = Horizontally position where you want to draw the bubble. Starts on the left side from
0 (Zero).
b) y = Vertically position where you want to draw the bubble. Starts from the bottom with
value 0 (Zero).
c) title = The string you want to see on top of the bubble in a slightly bigger font size.
d) . . . = An optional set of strings for the text lines. Each line must be a single string
argument without an CR/LF in it.
The function bubble() is only allowed inside the drawing loop callback. So only use it with
do_every_draw() – or you will see no result. The two returned arguments will give you the
maximum x and y screen coordinate the bubble will use.
The scripts QNH_helper.lua and bubble copilot.lua will show you some examples how to
use bubbles.
2.2.58 hight, width = big_bubble( x, y, "title", . . . )

The same as bubble(), but with a bigger font size.

Page 40 of 129

2.2

Lua functions

2

REFERENCE

2.2.59 hight, width = huge_bubble( x, y, "title", . . . )

The same as bubble(), but with a much bigger font size.
2.2.60 add_macro( "macro name", "Lua code string" )

a) macro name = Name of the macro. This string is used for the menu entry.
b) Lua code string = A string containing Lua code you want to be calculated when the user
clicks on the menu entry.
Make a menu entry to calculate a little piece of Lua code on demand.
2.2.61 add_ATC_macro( "macro name", "Lua code string" )

a) macro name = Name of the macro. This string is used for the menu entry.
b) Lua code string = A string containing Lua code you want to be calculated when the user
clicks on the menu entry.
Make a menu entry to calculate a little piece of Lua code on demand. Menu entry will be
created inside the ATC menu, instead of the macro menu. Nice to collect some radio settings for
recurrent situations like flying home to your base airport. Can save a lot of clicks.
2.2.62 add_macro( "macro name", "activation code string", "deactivation code string",
"default state" )

a) macro name = Name of the macro. This string is used for the menu entry.
b) activation code string = A string containing Lua code you want to be calculated when the
user turns on the menu item.
c) deactivation code string = A string containing Lua code you want to be calculated when
the user turns off the menu item.
d) default state = A string either "activate" or "deactivate" to define the default state of
the menu entry.
Creating a menu entry with a switch. Only possible for macro menu, not for the ATC menu. See
the tutorial above for an example (auto setting the transponder).

Page 41 of 129

2.2

Lua functions

2

REFERENCE

2.2.63 create_command( "command name", "command description", "begin code
string", "continue code string", "end code string" )

a) command name = Name of the command, as X-Plane wants it to be (slash separated).
b) command description = A string describing your command. Can be found in X-Plane’s
keyboard and joystick menu.
c) begin code string = A string containing Lua code you want to be calculated when the
command begins.
d) continue code string = A string containing Lua code you want to be calculated when the
command continues (one per frame).
e) end code string = A string containing Lua code you want to be calculated when the command ends.
Creates a classic custom command. As you can check button states and call Lua functions direct
in every frame loops, custom commands are pretty useless.
If you want to script a classic command to provide a nice new feature to the X-Plane universe,
keep in mind that all of your little script have to contain classic code. Do not use modern
code (variables connected to DataRefs). You will never know if the user, who downloaded your
custom command script file, will use the same writable DataRef with a different variable name.
If so, FlyWithLua will stop working and presents an error message.
Attention: Never use a custom command name like "sim/...", or Austin will kill you.
There is a demo script »test command.lua«, showing how to use this powerful feature. And
the QNH tool »automatic set qnh.lua« will also provide a custom command.
2.2.64 table = directory_to_table( "path" )

a) table = A variable you want to be filled with a Lua table containing all filenames inside
the given directory.
b) path = A string with the path of the directory. The path can be written in Unix stile,
independent from the OS FlyWithLua is running on.
Will return a simple table containing all filenames in alphabetical order. Only the filenames are
returned, without the path.

Page 42 of 129

2.2

Lua functions

2

REFERENCE

2.2.65 place_aircraft_at( "ICAO" )

a) ICAO = A string with the ICAO code of the airport you want to place the user to.
Lua will be stopped for a moment and the plane will be replaced. This can take some time, so
please be patient. Please remember that all Lua scripts will be reloaded after this action!
2.2.66 load_aircraft( "path and full filename" )

a) path and full filename = A string with the path of your file. The path can be written in
Unix stile, independent from the OS FlyWithLua is running on. You will need the full
filename including the ending.
Lua will be stopped for a moment and the plane will be changed. This can take some time, so
please be patient. Please remember that all Lua scripts will be reloaded after this action!
This is an example:
1

l o a d _ a i r c r a f t ( " A i r c r a f t / G e n e r a l A v i a t i o n / C e s s n a 172 SP / Cessna_172SP . a c f " )

2.2.67 load_situation( "path and full filename" )

a) path and full filename = A string with the path of your file. The path can be written in
Unix stile, independent from the OS FlyWithLua is running on. You will need the full
filename including the ending.
Lua will be stopped for a moment and the situation file will be loaded. This can take some time,
so please be patient. Please remember that all Lua scripts will be reloaded after this action!
This does the same as the menu item "File" -> "Load Situation".
2.2.68 save_situation( "path and full filename" )

a) path and full filename = A string with the path of your file. The path can be written in
Unix stile, independent from the OS FlyWithLua is running on. You will need the full
filename including the ending.
The current situation is written into a file. You will have to use the ending ".sit" for situation
files, to make sure that you can load them with X-Plane’s menu.
This does the same as the menu item "File" -> "Save Situation".

Page 43 of 129

2.2

Lua functions

2

REFERENCE

2.2.69 reload_scenery()

This will reload the scenery silently. But keep in mind that reloading the scenery will freeze the
simulation for a couple of time, depending on the complexity of your scenery and the power of
your CPU.
Reloading the scenery with this function call will not reload the scripts.
2.2.70 crash_the_sim()

Believe me, you will never ever want to know what this function does to your simulator.

Page 44 of 129

3

MODULES

3 Modules
You can write a module file to create new functions, predefined DataRefs, global variables or
whatever you need for more than one script file. The file must be named name you want.lua
and must be copied into this folder:
«place where you store the sim»/X-Plane 10/Resources/plugins/FlyWithLua/Modules/
For the more advanced Lua coders, the Lua engine will look for modules inside the folder named
above with the search pattern:
"?.lua;?/init.lua"
If you do not understand it, don’t matter. This will be a quick and ugly info:
Create a file with an ending .lua and start with a first line exactly as shown:
1

module ( . . . , p a c k a g e . s e e a l l ) ;

2
3
4
5
6

−− h e r e comes y o u r own c o d e
function say_hello ()
X S B S p e a k S t r i n g ( " H e l l o World ! " )
end

When the first line is spelled 100% correct, you can get access to the module from every script
inside the Scripts folder. Just start with the name of the module followed by "." (a dot)
followed by what you want to access. If you named the file shown above "nonsense.lua", then
you can write a script like this.
1

require ( " nonsense " )

2
3
4

−− l e t ’ s s a y h e l l o
nonsense . say_hello ( )

In all files you want access to your module, you have to start the script with a Lua command
require(), to tell Lua which module you want to use. If you want access to more than one
module, use multiple require() commands.
3.1 The Radio Module

If you start your script with a line like this:
require("radio")
you will get all major DataRefs writable to access to the radios. They are:
COM1, COM2, COM1_STDBY, COM2_STDBY, NAV1, NAV2, NAV1_STDBY, NAV2_STDBY,
ADF1, ADF2, ADF1_STDBY, ADF2_STDBY, DME, DME_STDBY, OBS1, OBS2,
SQUAWK (0000 to 7777), TRANSPONDER\_MODE (0=off, 1=standby, 2=on, 3=test) and HDG.

Page 45 of 129

3.2

The XSquawkBox Module

3

MODULES

3.2 The XSquawkBox Module

To access all common DataRefs provided by XSquawkBox, you should start your script with:
require("XSquawkBox")
The DataRefs are:
XSB_VERS_NUMBER,XSB_VERS_STRING, XSB_CON_CALLSIGN, XSB_CON_SERVER,
XSB_CON_PORT, XSB_CON_PILOT_ID, XSB_CON_PASSWORD, XSB_CON_REALNAME,
XSB_CON_MODEL, XSB_CON_STATUS, XSB_FP_FLIGHT_TYPE, XSB_FP_TCAS_TYPE,
XSB_FP_NAV_TYPE, XSB_FP_SPEED, XSB_FP_DEPARTURE_AIRPORT,
XSB_FP_DEPARTURE_TIME, XSB_FP_DEPARTURE_TIME_ACTUAL, XSB_FP_CRUISE_ALTITUDE,
XSB_FP_ARRIVAL_AIRPORT, XSB_FP_ENROUTE_HRS, XSB_FP_ENROUTE_MINS,
XSB_FP_FUEL_HRS, XSB_FP_FUEL_MINS, XSB_FP_ALTERNATE_AIRPORT, XSB_FP_REMARKS,
XSB_FP_ROUTE, XSB_MIC_OPEN and XSB_MIC_ENABLED.
The DataRefs XSB_VERS_NUMBER, XSB_VERS_STRING, XSB_CON_STATUS and XSB_MIC_OPEN
are readonly, all other DataRefs are writable. Look into the module file XSquawkBox.lua and
study the XSquawkBox documentation, to find out how they work.
Independent from the module, you get these functions to command the XSquawkBox plugin:
3.2.1 XSBConnect()

Connects the plugin to VATSIM, using the login data from the DataRefs. No login dialog will
be shown.
3.2.2 XSBUserLogin()

Nearly the same as XSBConnect(), but it will show the login dialog and stop. The user can take
a look at the data and click on »connect« or »cancel«. If you are unsure what function is the best
to connect to VATSIM by a lua script, choose this. (You will not surprise the user.)
3.2.3 XSBDisconnect()

Disconnects from the VATSIM network instantly, without any dialog.

Page 46 of 129

3.3

The Bit Module

3

MODULES

3.2.4 XSBShowFlightplan()

Shows the flightplan dialog of XSquawkBox. The flightplan uses the DataRefs defined by the
module, so you can preload them with data before calling XSquawkBox to show the flightplan
dialog. The user can click on »send« or »cancel«.
If he cancels the dialog, all changes are not put into the DataRefs. If he sends the plan to the
VATSIM server, changes to the values are put into the DataRefs (the next time a per-frame call
starts, section »Understanding PLCs« explains why).
3.2.5 XSBSendFlightplan()

This function fires the flightplan filled by the DataRefs directly to VATSIM, without any dialog.
This behavior can surprise a user, so use it with care!
3.2.6 frequency = XSBLookupATC( "name string" )

This function wants a string as it’s argument and returns an integer value showing the frequency
of the ATC you ask for, or 0 (zero) if a controller with the given name is not online. This allows
a script like this:
1

local informed_the_user = false

2
3
4
5
6
7
8

function check_Wooge_service ( )
i f XSBLookupATC ( "EDWG_I_TWR" ) == 12240 and i n f o r m e d _ t h e _ u s e r == f a l s e t h e n
p r i n t ( " H u r r a ! H u r r a ! Wooge i s t b e s e t z t ! " )
informed_the_user = true
end
end

9
10

do_sometimes ( " check_wooge_service ( ) " )

The unit of the return value is 10 kHz, to get it compatible to X-Plane’s DataRefs (see module
radio). The original value returned by XSquawkBox uses the unit 1 kHz, FlyWithLua makes
the translation for you.
3.3 The Bit Module

The Bit module is included as a part of the LuaJIT system. A documentation to bitwise operations provided by these module can be found here:
http://bitop.luajit.org/
To use the Bit module, simply start your script with:
require("bit")

Page 47 of 129

4

OPENAL SOUND

4 OpenAL sound
Since version 2.3 FlyWithLua supports OpenAL sound. The OpenAL sound system is part of
X-Plane, so no additional library or module is needed. But before you play a sound, you must
understand how the sound system works.
4.1 Buffers, Sounds and Listeners

If you are familiar with OpenAL, you know that the sound system uses tree parts, buffers, sounds
and listeners. FlyWithLua combines these different parts into one table, where all the sound
stuff is stored. So forget everything you know about OpenAL and think about sound as system
represented by only one big table. If you force FlyWithLua to write a debug file, you will see
the sound system table (if it contains sounds).
4.2 Loading and defining sounds

To use the sound system, you first have to load a sound file into memory. At the moment, only
WAV files are allowed, no MP3 or OGG files.
You fill the sound system table by loading a WAV file and remembering the position inside
the table. The first sound you load gets number 0 (zero), as this is typical for C++ plugins
(FlyWithLua is written in C/C++).
4.2.1 table position = load_WAV_file( filename )

a) table position = The index value, where your file is stored into the sound system table.
Index values starts from 0 (Zero).
b) filename = The name of the WAV file to load.
This function loads a WAV file into the sound system table and gives back the index value. This
is an example:
1

r o t a t e _ s o u n d = load_WAV_file ( SCRIPT_DIRECTORY . . " s o u n d s / r o t a t e . wav " )

After you have loaded a sound file, you can define some parameters to the sound, like the loop,
pitch and gain value. By default, a sound is only played once (loop = false), with normal pitch
(pitch = 1.0) and full gain (gain = 1.0). If you want other than the default values, modify them
with these functions:

Page 48 of 129

4.2

Loading and defining sounds

4

OPENAL SOUND

4.2.2 let_sound_loop( table position, boolean value )

a) table position = The index value, where your file is stored into the sound system table.
Index values starts from 0 (Zero).
b) boolean value = This has to be true, if the sound should loop, else false.
4.2.3 set_sound_pitch( table position, float value )

a) table position = The index value, where your file is stored into the sound system table.
Index values starts from 0 (Zero).
b) float value = The value for the pitch. The default value is 1.0 for an unmodified, normal
pitch.
4.2.4 set_sound_gain( table position, float value )

a) table position = The index value, where your file is stored into the sound system table.
Index values starts from 0 (Zero).
b) float value = The value for the gain. The default value is 1.0 for full gain.
Here is an example:
1
2
3
4
5

−− l o a d s o u n d " c a b i n crew , p r e p a r e f o r l a n d i n g "
c c _ p r e p a r e _ l a n d i n g _ s o u n d = load_WAV_file ( SCRIPT_DIRECTORY . . " s o u n d s / c c p r e p l a n d . wav " )
−− f a s t s p e a k i n g , h e l i u m b r e a t h i n g p i l o t w h i s p e r i n g
set_sound_pitch ( cc_prepare_landing_sound , 1.8)
set_sound_gain ( cc_prepare_landing_sound , 0.25)

4.2.5 unload_all_sounds( )

This will unload all sounds from memory. After this the sound system table is enpty and all your
stored index values are useless.
FlyWithLua uses this function to clean up the memory before reloading all scripts. You should
avoid to directly access this cleanup, if you want to share your script, or other scripts of the users
can be crashed by killing there sounds.

Page 49 of 129

4.2

Loading and defining sounds

4

OPENAL SOUND

4.2.6 replace_WAV_file(table position, filename )

a) table position = The index value, where your file is stored into the sound system table.
Index values starts from 0 (Zero).
b) filename = The name of the WAV file to load.
This function loads a WAV file into a given position of the sound system table. The position
must contain a sound file, as this function only replaces the WAV buffer in memory. You can’t
create a new element in the sound system table.
You can use this to adjust the content of sounds. This is an example:
1

...

2
3
4

−− l o a d s o u n d " Good m o r n i n g S i r "
welcome_sound = load_WAV_file ( SCRIPT_DIRECTORY . . " s o u n d s / g o o d m o r n i n g . wav " )

5
6

...

7
8
9
10

function teach_copilot_Frisian ()
r e p l a c e _ W A V _ f i l e ( welcome_sound , SCRIPT_DIRECTORY . . " s o u n d s / moinmoin . wav " )
end

Page 50 of 129

4.3

Using the sounds from the sound table

4

OPENAL SOUND

4.3 Using the sounds from the sound table

After you filled the sound system table with WAV files and all parameters are defined, you can
use the sounds by using these functions:
4.3.1 play_sound( table position )

a) table position = The index value, where your sound is stored into the sound system table.
Index values starts from 0 (Zero).
This functions starts playing the sound at the given index. If the loop parameter is set to false
(the dafault value), playing will stop automatically, else it will restart from the beginning until
you stop the sound.
4.3.2 stop_sound( table position )

a) table position = The index value, where your sound is stored into the sound system table.
Index values starts from 0 (Zero).
This functions stops the sound at the given index. This is especially useful, if the sound is forced
to loop. FlyWithLua will not remember the position (duration) where you stop the sound.
4.3.3 pause_sound( table position )

a) table position = The index value, where your sound is stored into the sound system table.
Index values starts from 0 (Zero).
This functions pause the sound at the given index. This is especially useful, if the sound is forced
to loop. FlyWithLua will remember the position (duration) where you pause the sound. When
you call the play_sound() function the next time, it will continue at this position (duration).
4.3.4 rewind_sound( table position )

a) table position = The index value, where your sound is stored into the sound system table.
Index values starts from 0 (Zero).
This functions rewinds the sound at the given index. In other words, the sound will continue at
the beginning position, if you restart playing.

Page 51 of 129

5

OPENGL GRAPHICS

5 OpenGL graphics
If you want to draw more than text, you can get directly access to a few OpenGL functions.
All OpenGL functions provided by FlyWithLua will not check the arguments!
This is a performance issue. OpenGL is for advanced coders only. If you make a mistake and
send a nil argument direct into your graphic card, it’s your blame seeing the hellfire of a black
hole eating up your computer hardware. ;)
5.1 Functions of OpenGL

FlyWithLua provides these OpenGL stuff:
5.1.1 glBegin_POINTS()
5.1.2 glBegin_LINES()
5.1.3 glBegin_LINE_STRIP()
5.1.4 glBegin_LINE_LOOP()
5.1.5 glBegin_POLYGON()
5.1.6 glBegin_TRIANGLES()
5.1.7 glBegin_TRIANGLE_STRIP()
5.1.8 glBegin_TRIANGLE_FAN()
5.1.9 glBegin_QUADS()
5.1.10 glBegin_QUAD_STRIP()
5.1.11 glEnd()
5.1.12 glVertex2f(x, y)
5.1.13 glVertex3f(x, y, z)

Page 52 of 129

5.1

Functions of OpenGL

5

OPENGL GRAPHICS

5.1.14 glLineWidth(width)
5.1.15 glColor3f(red, green, blue)
5.1.16 glColor4f(red, green, blue, alpha)
5.1.17 glRectf(x1, y1, x2, y2)

All arguments are float numbers, but as Lua don’t know the difference between int, float and
double, you can fire into your graphic card any type of number, as long as it’s not a string or
table.
Important: FlyWithLua draws when X-Plane is in "window draw state". Everything you can
do is drawing 2D with screen pixel coordinates starting from left bottom. The x argument is
"pixels to the right", the y arguments is "pixels up". The z coordinate must be 0 (zero), or you
will not see what you want to draw.
So glVertex3f() is pretty useless at the moment. It is included for further versions of FlyWithLua. The same for glColor4f, as the window draw state ignores the alpha values.7
If you want more graphic features, than you might better use other tools like SASL.
You should not change OpenGL states directly. Use the XPLMSetGraphicsState() function instead. This function can be accessed directly through FlyWithLua (without any error checking!).
5.1.18 XPLMSetGraphicsState(EnableFog, NumberTexUnits, EnableLighting,
EnableAlphaTesting, EnableAlphaBlending, EnableDepthTesting,
EnableDepthWriting)

Sets the OpenGL graphics state. All arguments are integers, 1 is on, 0 is off.
FlyWithLua starts every drawing with
XPLMSetGraphicsState(0,0,0,1,1,0,0)

-- set alpha testing and blending on

The line above is executed before everything from do_every_draw() is done. But commands
from other scripts may change the state, so you should always reset the state before you draw
any 2D stuff.

7 This

is no longer true in FlyWithLua 2.0, but you have to use XPLMSetGraphicsState() when a draw_string()
function is used.

Page 53 of 129

6

THE GRAPHICS MODULE

6 The graphics module
If you start a script with a line like require("graphics"), you will be able to use all functions
delivered by the graphics module.
6.1 Functions of graphics module

The functions are:
6.1.1 x_result, y_result = graphics.move_angle( x, y, angle, length )

a) x = Horizontal position where your calculation starts (left begins with 0).
b) y = Vertical position where your calculation starts (bottom begins with 0).
c) angle = Angle to the point you are interested in. A value of 0 will point upwards, values
go clockwise (90 is to the right, 180 is downwards, 270 is to the left).
d) length = The length of your (virtual) line in pixel.
e) x_result = The horizontal coordinate in screen pixel of the end point of your (virtual) line.
f) y_result = The vertical coordinate in screen pixel of the end point of your (virtual) line.
A helper function used by other graphics functions to do the calculations. You may not need this
function directly.
6.1.2 graphics.draw_line( x1, y1, x2, y2 )

x1, y1 and x2, y2 are the screen coordinates of the start and end point of the line, you want to
draw.
6.1.3 graphics.draw_rectangle( x1, y1, x2, y2 )

x1, y1 and x2, y2 are the screen coordinates of two opposite corner points of the rectangle, you
want to draw.
6.1.4 graphics.draw_triangle( x1, y1, x2, y2, x3, y3 )

x1, y1 and x2, y2 and x3, y3 are the screen coordinates of the points of a triangle, you want to
draw.

Page 54 of 129

6.1

Functions of graphics module

6

THE GRAPHICS MODULE

6.1.5 graphics.set_color( red, green, blue, alpha )

a) red = A float value from 0.0 to 1.0 choosing the red part of a RGB color.
b) green = A float value from 0.0 to 1.0 choosing the green part of a RGB color.
c) blue = A float value from 0.0 to 1.0 choosing the blue part of a RGB color.
d) alpha = The alpha value (transparency) of the color. An alpha value of 1.0 will draw only
your stuff, a value of 0.0 makes it invisible. If the alpha arguments is missing, it will be
set to 1.0.
6.1.6 graphics.set_width( width )

a) width = The line width you want to use from now on.
6.1.7 graphics.draw_angle_line( x, y, angle, length )

a) x = Horizontal position where your line starts (left begins with 0).
b) y = Vertical position where your line starts (bottom begins with 0).
c) angle = Angle where to draw the line. A value of 0 will point upwards, values go clockwise (90 is to the right, 180 is downwards, 270 is to the left).
d) length = The length of your line in pixel.
Draws a line from a given point with a given angle and length. Very useful for drawing round
instruments.
6.1.8 graphics.draw_angle_arrow( x, y, angle, length, arrowhead’s length, line width )

a) x = Horizontal position where your arrow starts (left begins with 0).
b) y = Vertical position where your arrow starts (bottom begins with 0).
c) angle = Angle where to draw the arrow. A value of 0 will point upwards, values go
clockwise (90 is to the right, 180 is downwards, 270 is to the left).
d) length = The length of your arrow in pixel.
e) arrowhead’s length = The length of the arrowhead in pixel. When the value is missing,
7.5 will be used.
f) line width = The width of the line (default is 1).

Page 55 of 129

6.1

Functions of graphics module

6

THE GRAPHICS MODULE

Draws an arrow from a given point with a given angle and length. Very useful for drawing
round instruments. You can modify the design by choosing the width and the length of the
arrowhead.
6.1.9 graphics.draw_circle( x, y, radius, line width )

If you leave the line width argument away, a line width of 1.0 will be used.
6.1.10 graphics.draw_filled_circle( x, y, radius )

Draws a circle filled with the actual color.
6.1.11 graphics.draw_arc( x, y, start angle, end angle, radius, line width )

Draws an arc defined by a start and an end angle. If you leave the line width argument away, a
line width of 1.0 will be used.
6.1.12 graphics.draw_filled_arc( x, y, start angle, end angle, radius )

Draws an arc defined by a start and an end angle. The arc is filled with the actual color.
6.1.13 graphics.draw_tick_mark( x, y, angle, radius, length, width )

Draws a tick mark to the inner side of a given circle (by x, y, radius). The position of the tick
mark has to be set as an angle.
You can change the design of the inner tick mark line by setting it’s length and width. If you
leave the parameters away, the default length is 10.0 and the default width is 1.0.
This will only draw the tick mark, not the circle. So you can use it for circles and arcs.
6.1.14 graphics.draw_outer_tracer( x, y, angle, radius, size )

Draws an outer tracer (a little triangle) to a given circle (by x, y, radius). The position of the
tracer has to be set as an angle.
You can change the design of the tracer by setting it’s size. If you leave the size parameter away,
the default size of 7.5 will be used.
This will only draw the tracer, not the circle. So you can use it for circles and arcs.

Page 56 of 129

6.1

Functions of graphics module

6

THE GRAPHICS MODULE

6.1.15 graphics.draw_inner_tracer( x, y, angle, radius, size )

The same as before, but the little triangle will be placed inside the circle.

Page 57 of 129

7

HUD MODULE

7 HUD module
7.1 An Interactive HUD

Normally X-Plane has a forward view with HUD but all HUD elements are unchangeable given
by X-Plane, and they are not interactive. Since FlyWithLua 2.2 you can react on mouse clicks
and mouse wheel movement. So we made a little demo how to use it by creating the HUD
module.
The module allows to define multiples »HUDs«. A HUD, as defined by the module, is a rectangle area of the screen containing elements, who are rectangle areas as well.
7.2 An Example

Let’s start with an example.
1

r e q u i r e "HUD"

2
3

HUD. begin_HUD ( 1 0 0 , 2 0 0 , 8 0 , 4 5 , " MyExample " )

4
5
6

HUD. c r e a t e _ e l e m e n t ( " c a p t i o n " , 0 , 3 0 , 8 0 , 1 5 )
HUD. d r a w _ s t r i n g ( 1 2 , 3 , 1 0 , " H e l l o World ! " )

7
8

HUD. end_HUD ( )

Create a Lua script file with these code and execute it. Now change the view to forward with
HUD and you will see your result.
Seeing »Hello World!« isn’t really cool for pilots, so we modify the script a little bit.
1

r e q u i r e "HUD"

2
3

d a t a r e f ( " QNH_Pilot " , " sim / c o c k p i t 2 / g a u g e s / a c t u a t o r s / b a r o m e t e r _ s e t t i n g _ i n _ h g _ p i l o t " , "
writable " )

4
5

HUD. begin_HUD ( 1 0 0 , 2 0 0 , 8 0 , 4 5 , " MyExample " )

6
7
8

HUD. c r e a t e _ e l e m e n t ( " c a p t i o n " , 0 , 3 0 , 8 0 , 1 5 )
HUD. d r a w _ s t r i n g ( 1 2 , 3 , 1 0 , " H e l l o World ! " )

9
10
11
12

HUD. c r e a t e _ e l e m e n t ( " b a r o " , 0 , 0 , 8 0 , 3 0 )
HUD. d r a w _ s t r i n g ( 1 2 , 2 0 , 1 0 , "BARO" )
HUD. d r a w _ f s t r i n g ( 1 2 , 3 , 1 8 , " %2.2 f " , " QNH_Pilot " )

13
14

HUD. end_HUD ( )

Okay, this is a little more useful to pilots. We can see the barometer setting of the pilot’s altimeter.
The first lines of code are loading the module »HUD« and define a DataRef variable QNH_Pilot.
Then line no. 5 starts creating a HUD container. The parameters are x, y, width, hight and an

Page 58 of 129

7.2

An Example

7

HUD MODULE

unique name of the HUD container (useful to debug the code). The screen coordinates x and
y are from the bottom left corner of the screen. If you want them relative to the right or upper
border of the screen use negative values.
The parameters of the next function are relative to the HUD container. So 0, 30, 80, 15
meens a screen area from 100/230 to 180/245, as this is 0/30 to 80/45 inside the HUD container.
We always define elements by there lower left corner. If we have to define an area instead
of only a point, we add width and hight, not an upper right corner!
The same in line 8, the parameters 12, 20 points to 112/233 on the screen, as all sub-elements
are relative to there »mother« element or container.
This is a big advantage, as you can move the whole container or element, just by changing one
pair of parameters. All lower elements will follow there parents.
The function draw_fstring() allows us to format the output. The fourth parameter must be
a string, not an expression! If you forget the brackets around QNH_Pilot, your code won’t
work.
To make it even more useful, we will now add some interaction.
1

r e q u i r e "HUD"

2
3

d a t a r e f ( " QNH_Pilot " , " sim / c o c k p i t 2 / g a u g e s / a c t u a t o r s / b a r o m e t e r _ s e t t i n g _ i n _ h g _ p i l o t " , "
writable " )

4
5

HUD. begin_HUD ( −81 , −200 , 8 0 , 4 5 , " MyExample " )

6
7
8
9

HUD. c r e a t e _ e l e m e n t ( " c a p t i o n " , 0 , 3 0 , 8 0 , 1 5 )
HUD. d r a w _ s t r i n g ( 1 2 , 3 , 1 0 , " s e t t o STD" )
HUD. c r e a t e _ c l i c k _ a c t i o n ( 0 , 0 , 8 0 , 1 5 , " QNH_Pilot = 2 9 . 9 2 " )

10
11
12
13

HUD. c r e a t e _ e l e m e n t ( " b a r o " , 0 , 0 , 8 0 , 3 0 , 0 , 0 , 0 , 0 )
HUD. d r a w _ s t r i n g ( 1 2 , 2 0 , 1 0 , "BARO" )
HUD. d r a w _ f s t r i n g ( 1 2 , 3 , 1 8 , " %2.2 f " , " QNH_Pilot " )

14
15

HUD. end_HUD ( )

The first change is that we are now positioned from the upper right of the screen (see line
no. 5).
An element is made with a border around it. You can give the color values red, green, blue and
alpha. By making alpha 0 (zero), the border will be invisible (see line no. 11).
The most important change is in line no. 9. We define an action, when the user (pilot) clicks
inside the element. The action itself must be given as a string, not as an expression.
But we are not limited to mouse clicks. We can also react on mouse wheel movements. Let’s
modify the code once again.

Page 59 of 129

7.2

1

An Example

7

HUD MODULE

r e q u i r e "HUD"

2
3

d a t a r e f ( " QNH_Pilot " , " sim / c o c k p i t 2 / g a u g e s / a c t u a t o r s / b a r o m e t e r _ s e t t i n g _ i n _ h g _ p i l o t " , "
writable " )

4
5

HUD. begin_HUD ( −81 , −200 , 8 0 , 4 5 , " MyExample " )

6
7
8
9

HUD. c r e a t e _ e l e m e n t ( " c a p t i o n " , 0 , 3 0 , 8 0 , 1 5 )
HUD. d r a w _ s t r i n g ( 1 2 , 3 , 1 0 , " s e t t o STD" )
HUD. c r e a t e _ c l i c k _ a c t i o n ( 0 , 0 , 8 0 , 1 5 , " QNH_Pilot = 2 9 . 9 2 " )

10
11
12
13
14

HUD.
HUD.
HUD.
HUD.

c r e a t e _ e l e m e n t ( " baro " , 0 , 0 , 80 , 30 , 0 , 0 , 0 , 0)
d r a w _ s t r i n g ( 1 2 , 2 0 , 1 0 , "BARO" )
d r a w _ f s t r i n g ( 1 2 , 3 , 1 8 , " %2.2 f " , " QNH_Pilot " )
c r e a t e _ w h e e l _ a c t i o n ( 0 , 0 , 8 0 , 3 0 , " QNH_Pilot = QNH_Pilot + MOUSE_WHEEL_CLICKS / 100
")

15
16

HUD. end_HUD ( )

One more line of code adds a lot of additional fun. In line no. 14 we create a reaction on mouse
wheel movement. The variable MOUSE_WHEEL_CLICKS is a read-only FlyWithLua predefined
variable. It’s value is positive or negative depending on the direction of the movement.
Now we make the last modification of the example.
1

r e q u i r e "HUD"

2
3
4

d a t a r e f ( " QNH_Pilot " , " sim / c o c k p i t 2 / g a u g e s / a c t u a t o r s / b a r o m e t e r _ s e t t i n g _ i n _ h g _ p i l o t " , "
writable " )
d a t a r e f ( "GPU" , " sim / c o c k p i t / e l e c t r i c a l / gpu_on " , " w r i t a b l e " )

5
6

HUD. begin_HUD ( −81 , −200 , 8 0 , 4 5 , " MyExample " )

7
8
9
10

HUD. c r e a t e _ e l e m e n t ( " c a p t i o n " , 0 , 3 0 , 8 0 , 1 5 )
HUD. d r a w _ s t r i n g ( 1 2 , 3 , 1 0 , " s e t t o STD" )
HUD. c r e a t e _ c l i c k _ a c t i o n ( 0 , 0 , 8 0 , 1 5 , " QNH_Pilot = 2 9 . 9 2 " )

11
12
13
14
15

HUD.
HUD.
HUD.
HUD.

c r e a t e _ e l e m e n t ( " baro " , 0 , 0 , 80 , 30 , 0 , 0 , 0 , 0)
d r a w _ s t r i n g ( 1 2 , 2 0 , 1 0 , "BARO" )
d r a w _ f s t r i n g ( 1 2 , 3 , 1 8 , " %2.2 f " , " QNH_Pilot " )
c r e a t e _ w h e e l _ a c t i o n ( 0 , 0 , 8 0 , 3 0 , " QNH_Pilot = QNH_Pilot + MOUSE_WHEEL_CLICKS / 100
")

16
17

HUD. end_HUD ( )

18
19
20
21
22
23
24

HUD. begin_HUD ( 1 0 0 , 1 , 3 0 , 1 2 , "GPU" , " a l w a y s " )
HUD. c r e a t e _ e l e m e n t ( "GPU" , 0 , 0 , 3 0 , 1 2 )
HUD. d r a w _ s t r i n g ( 4 , 2 , 1 0 , "GPU" )
HUD. c r e a t e _ b a c k l i g h t _ i n d i c a t o r ( 0 , 0 , 3 0 , 1 2 , "GPU == 1 " , 0 , 1 , 0 , 0 . 5 )
HUD. c r e a t e _ c l i c k _ s w i t c h ( 0 , 0 , 3 0 , 1 2 , "GPU" , 0 , 1 )
HUD. end_HUD ( )

Lines 19 to 24 define another HUD container. The additional container is defined as "always",
so it will appear if the mouse hovers over it, no matter of the view mode.
You find the example file as HUD module example.lua and an even more complex script
HUD module test.lua in the Scripts (disabled) folder.

Page 60 of 129

7.3

Functions from HUD module

7

HUD MODULE

7.3 Functions from HUD module
7.3.1 HUD.begin_HUD( x, y, width, hight, "name", "always" )

a) x = Horizontal position of the HUD container’s lower left corner. Use negative value to
get relative to the right screen border.
b) y = Vertical position of the HUD container’s lower left corner. Use negative value to get
relative to the upper screen border.
c) width = The width in pixel.
d) hight = The hight in pixel.
e) name = The name of the container. A string for debugging only.
f) "always" = If this optional string is given as the last parameter, the container will always
be visible if the mouse hovers over it. Otherwise it will be visible in forward with HUD
view mode only.
This starts the description of a container. A must use function, or you will never see something
on your screen.
7.3.2 HUD.end_HUD( )

This ends the description of a container, generates a Lua script file and executes this file. This
can be followed by the next container, as long as the container names are different.
7.3.3 HUD.create_element( "name", x, y, width, hight, red, green, blue, alpha )

a) name = The name of the element. A string for debugging only.
b) x = Horizontal position of the element relative to it’s container. Negative values are not
allowed.
c) y = Vertical position of the element relative to it’s container. Negative values are not
allowed.
d) width = The width in pixel.
e) hight = The hight in pixel.
f) red, green, blue, alpha = OpenGL color code of the border around the element. All values
are floating point numbers from 0.0 (zero) to 1.0 (one).
Creates an element. Elements can contain strings, colored indicators and actions. There is no
HUD.end_element() function. Just start the next element or close the HUD description.

Page 61 of 129

7.3

Functions from HUD module

7

HUD MODULE

7.3.4 HUD.draw_string( x, y, fontsize, "string", red, green, blue, alpha )

a) x = Horizontal position of the string relative to it’s element.
b) y = Vertical position of the string relative to it’s element.
c) fontsize = The size of the font. Value can be 8, 10, 12 or 18.
d) "string" = The string to be printed.
e) red, green, blue, alpha = OpenGL color code of the border around the element. All values
are floating point numbers from 0.0 (zero) to 1.0 (one).
This will draw a string inside the element. Keep in mind that all coordinates are relative to the
parent. The string will be printed directly onto the screen without any evaluation.
7.3.5 HUD.draw_fstring( x, y, fontsize, "format", "expression", red, green, blue, alpha )

a) x = Horizontal position of the string relative to it’s element.
b) y = Vertical position of the string relative to it’s element.
c) fontsize = The size of the font. Value can be 8, 10, 12 or 18.
d) "format" = The format string, as used by Lua’s string.format() function.
e) "expression" = A string to be evaluated to get the values for the format string.
f) red, green, blue, alpha = OpenGL color code of the border around the element. All values
are floating point numbers from 0.0 (zero) to 1.0 (one).
If you want to print variable values, use the HUD.draw_fstring() function. The output can be
well formatted, as known from the string.format() function in pure Lua.
7.3.6 HUD.create_backlight_indicator( x, y, width, hight, "condition", red, green, blue,
alpha )

a) x = Horizontal position of the area relative to the element.
b) y = Vertical position of the area relative to the element.
c) width = The width in pixel.
d) hight = The hight in pixel.
e) "condition" = A string containing a Lua expression that can be evaluated as true or false.
f) red, green, blue, alpha = OpenGL color code of the background. All values are floating
point numbers from 0.0 (zero) to 1.0 (one).

Page 62 of 129

7.3

Functions from HUD module

7

HUD MODULE

If the expression results into true, the area will be filled with the given color.
7.3.7 HUD.create_click_action( x, y, width, hight, "action" )

a) x = Horizontal position of the click-sensitive area relative to the element.
b) y = Vertical position of the click-sensitive area relative to the element.
c) width = The width in pixel.
d) hight = The hight in pixel.
e) "action" = A string containing the Lua code to be executed when the user clicks into the
sensitive area.
If the user clicks into the sensitive area, the action will be done. This will always resume the
click.
7.3.8 HUD.create_click_switch( x, y, width, hight, "variable", value, alternative value )

a) x = Horizontal position of the click-sensitive area relative to the element.
b) y = Vertical position of the click-sensitive area relative to the element.
c) width = The width in pixel.
d) hight = The hight in pixel.
e) "variable" = The Lua variable to be set.
f) value = The value to be set.
g) alternative value = The alternative value.
If the user clicks into the sensitive area, the variable will be set to the value. But if it contains
the value, it will be set to the alternative value.

Page 63 of 129

7.3

Functions from HUD module

7

HUD MODULE

7.3.9 HUD.create_wheel_action( x, y, width, hight, "action" )

a) x = Horizontal position of the sensitive area relative to the element.
b) y = Vertical position of the sensitive area relative to the element.
c) width = The width in pixel.
d) hight = The hight in pixel.
e) "action" = A string containing the Lua code to be executed when the user moves the mouse
wheel inside the sensitive area.
If the user moves the mouse wheel while the mouse pointer is inside the sensitive area, the action
will be done. This will always resume the wheel movement.
You can use the predefined variable MOUSE_WHEEL_CLICKS to define the action. The variable is
positive or negative depending on the direction of the wheel movement. It’s value depends on
the operation system, on Windows you will get little integer steps.

Page 64 of 129

8

XPLMNAVIGATION

8 XPLMNavigation
You can use all functions from the XPLMNavigation SDK Part delivered by Sandy Barbour. Get
more info on it here:
http://www.xsquawkbox.net/xpsdk/mediawiki/XPLMNavigation
When you use the functions in Lua, you will have to use a different spelling, as Lua does not
need pointers to return more than one value. The correct spelling is shown in the following
function description.
8.1 Functions from XPLMNavigation
8.1.1 nav_reference = XPLMGetFirstNavAid()
8.1.2 next_nav_reference = XPLMGetNextNavAid( inNavAidRef )
8.1.3 first_nav_reference = XPLMFindFirstNavAidOfType( inType )
8.1.4 last_nav_reference = XPLMFindLastNavAidOfType( inType )
8.1.5 nav_reference = XPLMFindNavAid( inNameFragment, inIDFragment, inLat, inLon,
inFrequency, inType)
8.1.6 outType, outLatitude, outLongitude, outHeight, outFrequency, outHeading, outID,
outName = XPLMGetNavAidInfo( inRef )
8.1.7 index_count = XPLMCountFMSEntries()
8.1.8 index = XPLMGetDisplayedFMSEntry()
8.1.9 index = XPLMGetDestinationFMSEntry()
8.1.10 XPLMSetDisplayedFMSEntry( inIndex )
8.1.11 XPLMSetDestinationFMSEntry( inIndex )
8.1.12 outType, outID, outRef, outAltitude, outLat, outLon = XPLMGetFMSEntryInfo(
inIndex )

Page 65 of 129

8.1

Functions from XPLMNavigation

8

XPLMNAVIGATION

8.1.13 XPLMSetFMSEntryInfo( inIndex, inRef, inAltitude)
8.1.14 XPLMSetFMSEntryLatLon( inIndex, inLat, inLon, inAltitude)
8.1.15 XPLMClearFMSEntry( inIndex )

If you have to use inType or outType, you will have to manage integer values, not strings. You
can use the variables (Lua does not know constants) XPLM_NAV_NOT_FOUND, xplm_Nav_Unknown,
xplm_Nav_Airport, xplm_Nav_NDB, xplm_Nav_VOR, xplm_Nav_ILS, xplm_Nav_Localizer,
xplm_Nav_GlideSlope, xplm_Nav_OuterMarker, xplm_Nav_MiddleMarker, xplm_Nav_InnerMarker,
xplm_Nav_Fix, xplm_Nav_DME and xplm_Nav_LatLon.
The value outReg from XPLMGetNavAidInfo( inIndex ) will not be returned by Lua, because
it’s useless for your script. If you want a ninth value, you will always get a nil value.

Page 66 of 129

9

ACCESS HID DEVICES

9 Access HID devices
Since version 2.1 of FlyWithLua, you can access HID devices at low level. This is really cool
for cockpit builders. Normal users can skip this section.
9.1 Pre-defined variables
9.1.1 NUMBER_OF_HID_DEVICES

Integer value showing the number of HID devices, you can access from FlyWithLua.
9.1.2 ALL_HID_DEVICES

All HID devices found are stored in a table ALL_HID_DEVICES. The table has elements indexed
from 1 to NUMBER_OF_HID_DEVICES. Each elements has sub-elements. You can see all subelements when you write a debug file. Here is an example of the first HID device on my Windows 7 development system:
630
631
632
633
634
635
636
637
638
639

ALL_HID_DEVICES [ 1 ] . v e n d o r _ i d
= 1103 ( 0 x 4 4 f )
ALL_HID_DEVICES [ 1 ] . p r o d u c t _ i d
= 45322 ( 0 xb10a )
ALL_HID_DEVICES [ 1 ] . r e l e a s e _ n u m b e r
= 1280 ( 0 x500 )
ALL_HID_DEVICES [ 1 ] . i n t e r f a c e _ n u m b e r
= −1 ( 0 x f f f f f f f f )
ALL_HID_DEVICES [ 1 ] . u s a g e _ p a g e
= 1 ( 0 x1 )
ALL_HID_DEVICES [ 1 ] . u s a g e
= 4 ( 0 x4 )
ALL_HID_DEVICES [ 1 ] . p a t h
= \ \ ? \ h i d # v i d _ 0 4 4 f&p i d _ b 1 0 a #7&5 a04db4 &0&0000#{4
d1e55b2−f 1 6 f −11 c f −88cb −001111000030}
ALL_HID_DEVICES [ 1 ] . s e r i a l _ n u m b e r
= ?
ALL_HID_DEVICES [ 1 ] . m a n u f a c t u r e r _ s t r i n g = T h r u s t m a s t e r
ALL_HID_DEVICES [ 1 ] . p r o d u c t _ s t r i n g
= T . 1 6 0 0 0M

9.2 HID related functions

To access to HID devices, FlyWithLua uses a C-library HIDAPI from Alan Ott, Signal 11 Software. As Lua isn’t C, the function calls are different.
9.2.1 table, number = create_HID_table()

a) table = A table to be filled with the complete info about all HID devices found.
b) number = An integer representing the number of elements in the table.
Every time Lua restarts, it will generate a table and a number as a global variable set like shown
above. The code line to do this is:
ALL_HID_DEVICES, NUMBER_OF_HID_DEVICES = create_HID_table()

Page 67 of 129

9.2

HID related functions

9

ACCESS HID DEVICES

If you plug a device in or out, the global variables won’t change. As most of the pre-defined variables, they are filled when Lua (re)starts. There are dynamic pre-defined variables like MOUSE_X,
MOUSE_Y, SCREEN_WIDTH or SCREEN_HIGHT, but a dynamic filled variable consumes more CPU
time. As pluggin in and out devices is not a typical behavior of simulator pilots during flight,
the decision was not to listen to HID plugging events.
The function create_HID_table() will replace all the enumeration stuff from the original
HIDAPI library. Just examine the table ALL_HID_DEVICES if you need info generated by the
following functions not implemented into FlyWithLua:
hid_enumerate() and hid_free_enumerate()
9.2.2 device = hid_open( vendor_ID, product_ID )

a) device = A C-pointer to the object generated by the HIDAPI function to handle the HID
device (a userdata variable).
b) vendor_ID = The vendor ID of the device you want to open, an integer number.
c) product_ID = The product ID of the device you want to open, an integer number.
This will open the first device matching to your given IDs. Unlike the original library HIDAPI
you can’t search for a serial number. This is a limitation to Lua, that can’t handle wchar strings.
Use the next function, if you need to access a discrete device from a set of unique devices:
9.2.3 device = hid_open_path( path )

a) device = A C-pointer to the object generated by the HIDAPI function to handle the HID
device (a userdata variable).
b) path = The path representing the device you want to open. This string can be taken from
the global variable like: ALL_HID_DEVICES[n].path.
9.2.4 hid_close( device )

a) device = The pointer to the devices, given by the opening function.
This function closes a connection to a HID device. When Lua restarts, it automatically closes
all open connections to HID devices. It’s not a good way to create code, but if you like you can
forget to close the connections and let Lua do the work.

Page 68 of 129

9.2

HID related functions

9

ACCESS HID DEVICES

9.2.5 hid_write( device, report ID, value, ... )

a) device = The pointer to the devices, given by the opening function.
b) report ID = The report ID you want to write. For devices which only support a single
report, this must be set to 0 (zero).
c) value, ... = A set of integer values (range 0 to 255) to be written.
FlyWithLua will automatically count the number of values you give to the function hid_write,
unlike the original HIDAPI library, you can’t give a string plus number of elements.
9.2.6 nov, variable, ... = hid_read_timeout( device, nov wanted, milliseconds )

a) nov = A variable to store the number of values returned by the function. If the number
is lower than the number of variables you want to be filled, the variables without a return
value are filled with nil (typical to Lua).
b) variable, ... = A list of variables to store the values in.
c) device = The pointer to the devices, given by the opening function.
d) nov wanted = The number of values you want to receive.
e) milliseconds = The timeout in milliseconds the functions waits until receive process is
canceled.
You must provide a set of variables to store every byte of the returned message, not a single
string variable. If you are familiar to the original HIDAPI library, this may be unusual to you.
9.2.7 nov, variable, ... = hid_read_timeout( device, nov wanted )

The same as above, but without a timeout. If the device declines to answer, the simulator will
freeze. As this is normally not wanted, set the device connection to non-blocking:
9.2.8 success = hid_set_nonblocking( device, nonblock )

a) success = A variable to check if the execution was successfully. If the function does it’s
job right, the return value will be 0 (zero), otherwise it returns -1.
b) device = The pointer to the devices, given by the opening function.
c) nonblock = Defines if the connection should be non-blocking (set this value to 1) or blocking (set this value to 0).

Page 69 of 129

9.2

HID related functions

9

ACCESS HID DEVICES

9.2.9 nobw = hid_send_feature_report( device, report ID, value, ... )

a) nobw = The number of bytes written by the function. Use it to control, if the function
completes it’s job as expected. The number of bytes should be equal to the number of
values plus one for the report ID. In case of an error, it will return -1.
b) device = The pointer to the devices, given by the opening function.
c) report ID = The report ID you want to write. For devices which only support a single
report, this must be set to 0 (zero).
d) value, ... = A set of integer values (range 0 to 255) to be written.
This function sends a feature report to the HID device.
Time for an example? Let’s set the brightness of a Saitek BIP panel to 80%.
1
2

−− d e f i n e t h e b r i g h t n e s s we want t o s e t ( r a n g e 0 t o 1 0 0 )
B I P _ b r i g h t n e s s = 80

3
4
5

−− v e n d o r ID and p r o d u c t ID f o r a BIP = 0 x6a3 and 0 x b 4 e
m y _ f i r s t _ B I P = h i d _ o p e n ( 0 x6a3 , 0 xb4e )

6
7
8
9
10
11
12
13

−− c h e c k i f t h e d e v i c e was o p e n e d and s e t b r i g h t n e s s
i f m y _ f i r s t _ B I P == n i l t h e n
p r i n t ( "Oh , no ! We can ’ t f i n d o u r BIP p a n e l ! " )
else
−− 0 xb2 = r e p o r t ID f o r b r i g h t n e s s
h i d _ s e n d _ f e a t u r e _ r e p o r t ( m y _ f i r s t _ B I P , 0 xb2 , B I P _ b r i g h t n e s s )
end

14
15
16

−− c l o s e t h e c o n n e c t i o n t o t h e d e v i c e
hid_close ( my_first_BIP )

As you can see, we ignored the return value ot the function hid_sent_feature_report().
This is allowed, and we control the function by observing the panel brightness with our eyes.
9.2.10 nobw = hid_send_filled_feature_report( device, report ID, nobts, value, ... )

a) nobw = The number of bytes written by the function. Use it to control, if the function
completes it’s job as expected. The number of bytes should be equal to the number of
values plus one for the report ID. In case of an error, it will return -1.
b) device = The pointer to the devices, given by the opening function.
c) report ID = The report ID you want to write. For devices which only support a single
report, this must be set to 0 (zero).
d) nobts = The number of bytes to send. If you give too less values, it will be filled up with
zeros.
e) value, ... = A set of integer values (range 0 to 255) to be written.

Page 70 of 129

9.3

The Arcaze USB module

9

ACCESS HID DEVICES

This function sends a feature report to the HID device like the one above. The only difference
is, that it can fill up the data to send with zeros to a given lenght of data.
9.2.11 nobr, report ID, variable, ... = hid_get_feature_report( device, novw )

a) nobr = Number of bytes received (including the report ID).
b) report ID = The report ID the device sends.
c) variable, ... = A list of variables to store the values in.
d) device = The pointer to the devices, given by the opening function.
e) novw = Number of values we want to receive. This will not include the report ID!
Never confuse the number of bytes with the number of values. If you want to receive a feature
report containing four bytes of data, use this line of code:
novr, report_id, one, two, three, four = hid_get_feature_report(my_device, 4)
9.3 The Arcaze USB module

If you want to build your own home cockpit, but you don’t like the prebuild systems, why not
building your own design. With a little USB board you are able to communicate with FlyWithLua using USB HID feature reports. I will demonstrate this with an example using the Arcaze
USB board and his additional display driver board. Both are relative cheap hardware and you
can order it here:
http://simple-solutions.de
Of course this will work with every other hardware too, so why should you use the Arcaze USB
device? Because it’s very well documented:
http://wiki.simple-solutions.de/en/products/Arcaze/Arcaze-USB/Arcaze-USB_SDK/
Feature_Report_Protocol
In FlyWithLua there is a module to access the Arcaze device via USB HID feature reports.
Even if you have absolutely no idea of feature reports, it’s very easy to use the Arcase with the
included module. The first thing to do is loading the module, if you want to get access to it.
require "arcaze"
Start your script with this line, to load the module.
Then you will have to connect to the device. Let’s say you have only one Arcaze connected, so
we can do this:
my_arcaze = arcaze.open_first_device()

Page 71 of 129

9.3

The Arcaze USB module

9

ACCESS HID DEVICES

Please remember to start all commands from a module with the name of the module and a dot
between the name and the command.
After that, the variable my_arcase will contain a handle to the device. If you have more than
one device, this is the way you identify them.
If the pins A1 and A2 are connected to a rotary encoder, we can read it’s relative position
value.
encoder_value = arcaze.read_encoders( my_arcaze )
Now we want to show the value of the encoder on the seven-segment-display. We connect a
six element display to the display driver 32 board at channel »2A«. First we init the display
driver:
arcaze.init_display( my_arcaze, "2A", 15, 6)
This little line of code shows the value:
arcaze.show(my_first_arcaze, "2A", 0xff, encoder_value)
Repeat the reading and writing every frame to play around with the little Arcaze board.
Here are all functions the arcaze module provides:
9.3.1 device = arcaze.open_first_device()

a) device = The pointer to the devices, or -1 if it fails to open the Arcaze USB.
This will open the first Arcaze USB board FlyWithLua will find. If there is no Arcaze to open,
the function will return -1 instead of the device handler.
9.3.2 A1, A2, A3, ..., B19, B20 = arcaze.read_pins( device )

a) A1, A2, A3, ..., B19, B20 = The variables to be filled with the pins values (0 or 1).
b) device = The pointer to the devices, given by the opening function.
This will fill up to 40 variables with the value 0 (zero) or 1 (one), depending on the input pins
on the Arcaze Board. The first variable will be filled depending on the two pins labled A1, the
second depending on A2 and so on. If the pin pair is connected (closed), than a value of 1 is
returned, else the value is 0 (and the pin pair isn’t connected or open).
Use the underscore to skip a value. If the pin pairs A3 and A4 are connected to a rotary encoder,
and A1, A2 and A5 should control battery, avoinics and generator switch, than you can write a
little script like this:

Page 72 of 129

9.3

1

The Arcaze USB module

9

ACCESS HID DEVICES

require " arcaze "

2
3
4

−− open t h e d e v i c e
my_arcaze = a r c a z e . o p e n _ f i r s t _ d e v i c e ( )

5
6
7
8
9

−− u s e D a t a R e f s t o c o n t r o l t h e s i m
D a t a R e f ( " b a t t e r y " , " sim / c o c k p i t / e l e c t r i c a l / b a t t e r y _ o n " , " w r i t a b l e " )
D a t a R e f ( " a v o i n i c s " , " sim / c o c k p i t / e l e c t r i c a l / a v i o n i c s _ o n " , " w r i t a b l e " )
D a t a R e f ( " g e n e r a t o r " , " sim / c o c k p i t / e l e c t r i c a l / g e n e r a t o r _ o n " , " w r i t a b l e " , 0 )

10
11
12

−− s e t t h e D a t a R e f s by r e a d i n g p i n p a i r s A1 , A2 and A5
do_every_frame ( " b a t t e r y , a v o i n i c s , _ , _ , g e n e r a t o r = a r c a z e . r e a d _ p i n s ( my_arcaze ) " )

9.3.3 ADC1, ADC2, ADC3, ADC4, ADC5, ADC6 = arcaze.read_ADCs( device )

a) ADC1, ADC2, ADC3, ADC4, ADC5, ADC6 = The variables to be filled with the six ADC
values (range 0 to 4095).
b) device = The pointer to the devices, given by the opening function.
Read out the six analog values as 12-bit integer values. This is used to connect potis to XPlane.
9.3.4 E1, E2, E3, ..., E19, E20 = arcaze.read_encoders( device )

a) E1, E2, E3, ..., E19, E20 = The variables to be filled with the encoder values (range 0 to
65535).
b) device = The pointer to the devices, given by the opening function.
Encoders must be connected to pairs of pin pairs. The first encoder E1 must be connected to the
pin pairs A1 and A2, the last encoder E20 must be connected to the pin pairs B19 and B20.
The rotary encoder logic of the Arcaze USB board will produce a relative value between 0x0000
and 0xffff. It will count all positive and negative edges of both channels, so normally it makes 4
steps for each turn. The values can start whereever they want, so don’t expect 0x0000 when the
device is pluged into the USB port. See the example script little arcaze radio.lua to see
the usage of rotary encoders in detail.
9.3.5 arcaze.set_all_pins_for_input( device )

a) device = The pointer to the devices, given by the opening function.
All 40 pin pairs can be used as inputs or outputs. This function will set all pin pairs to input
mode. Use it before defining the output pins, to make tabula rasa.

Page 73 of 129

9.3

The Arcaze USB module

9

ACCESS HID DEVICES

9.3.6 arcaze.set_pin_direction( device, pin, direction )

a) device = The pointer to the devices, given by the opening function.
b) pin = The number of the pin pair to be set. Pin pair A1 is 0, B20 is 39.
c) direction = The direction to be set. Can be "input" or 0 for input direction, else use
"output" or 1 for output direction.
This will set the direction of a pin pair. Please remember that the number starts with 0, similar
to X-Plane’s joystick button numbers, as this is the standard counting of pure C code. You are
operating really low level here!
9.3.7 arcaze.set_pin( device, pin, value )

a) device = The pointer to the devices, given by the opening function.
b) pin = The number of the pin pair to be set. Pin pair A1 is 0, B20 is 39.
c) value = The value to be set. Can be "off" or 0 to open the output, else use "on" or 1 to
close the output pins.
This will set a pin pair. Please remember that the number starts with 0, similar to X-Plane’s
joystick button numbers, as this is the standard counting of pure C code. You should never set a
pin that is defined as an input pin!
9.3.8 arcaze.init_display( device, address, intensity, scan_limit )

a) device = The pointer to the devices, given by the opening function.
b) address = The address where the display unit is connected to, for example "1a" (range
"1a" to "4b", a string value). The address is printed onto the display driver board.
c) intensity = The value for the LED intensity (range 0 to 15).
d) scan_limit = The number of digits to be filled (range 4 to 8).
Use this once to initialize the display driver.

Page 74 of 129

9.3

The Arcaze USB module

9

ACCESS HID DEVICES

9.3.9 arcaze.init_display( device, address )

a) device = The pointer to the devices, given by the opening function.
b) address = The address where the display unit is connected to, for example "1a" (range
"1a" to "4b", a string value). The address is printed onto the display driver board.
If you let the intensity and scan limit away, FlyWithLua will guess an intensity of 15 (full) and
8 digits.
The display will show some nonsense data until you use this function:
9.3.10 arcaze.show( device, address, mask, value_string )

a) device = The pointer to the devices, given by the opening function.
b) address = The address where the display unit is connected to, for example "1a" (range
"1a" to "4b", a string value). The address is printed onto the display driver board.
c) mask = A bit mask of the digits to be set (range 0x00 to 0xff). If unsure, use 0xff.
d) value_string = The string to be displayed.
The mask will define the digits to be manipulated as a bit mask. If you say 0xff as the mask, all
eight digits will be set.
The value string is a string containing a numeric value. A decimal point "." can be used and the
negative sign "-". A space will left the digit blank.
All ports "1a", "2a", "3a" and "4a" are filled from right to left, so you can do this:
arcaze.show( my_arcaze, "1a", 0xff, "-4")
But on the left-filled ports, you should write a code like this:
arcaze.show( my_arcaze, "1b", 0xff, "

-4")

This code has six spaces in front of the substring "-4", to be shown on the right side of the
display.
See the example script little arcaze radio.lua to see the usage of seven segment displays.

Page 75 of 129

10

CLASSIC AND MODERN MODE

10 Classic and modern mode
Definition:
All scripts are »modern type« scripts, until you use one of the functions XPLMSetDatai(),
XPLMSetDataf(), XPLMSetDatad(), XPLMSetDatavi() or XPLMSetDatavf(). If a script uses
one of these functions, in FlyWithLua version 2.1 the use of dataref(), get(), set() and
set_array() is prohibited. Since version 2.2.1 you can mix them without any error.

The command XPLMSetDatab() is not possible in FlyWithLua, use a modern script file, if
you need access to string DataRefs. If performance is not an issue, you can try get() and
set(). Remember that the most important strings are in the predefined variables PLANE_ICAO,
PLANE_TAILNUMBER and XSB_METAR.
All modern script files work like a big PLC. You define the DataRefs you want as input and/or
output, and FlyWithLua handles all the value transfer from/to the simulator. No worry about
different types, clean code with perfect readability. But all the comfort you get will cost a little
bit of performance. If you are a performance fetishist wanting to squeeze out your CPU, but
you only have poor skills in C/C++, then you will probably want to write »classic mode« script
files.
Or in shorter words, classic mode leaves away the comfort and gives DataRef handling to your
responsibility. A big chance to get a super fast, ugly to read script code.
10.1 Reading classic functions

To pull a value out of the simulator, you must use one of the following functions, depending on
the type of the DataRef.
10.1.1 variable = XPLMGetDatai( DataRef )

a) variable = The lua variable, you want the value to be pushed in.
b) DataRef = The reference(!) of the DataRef you want to read out.
Reading out an integer DataRef. If the DataRef is not readable as an integer, the simulator may
blow up without a warning!

Page 76 of 129

10.1

Reading classic functions

10

CLASSIC AND MODERN MODE

10.1.2 variable = XPLMGetDataf( DataRef )

a) variable = The lua variable, you want the value to be pushed in.
b) DataRef = The reference(!) of the DataRef you want to read out.
Reading out a float DataRef. If the DataRef is not readable as a float, the simulator may blow up
without a warning!
10.1.3 variable = XPLMGetDatad( DataRef )

a) variable = The lua variable, you want the value to be pushed in.
b) DataRef = The reference(!) of the DataRef you want to read out.
Reading out a double DataRef. If the DataRef is not readable as a double, the simulator may
blow up without a warning!
10.1.4 table = XPLMGetDatavi( DataRef, inIndex, inMax )

a) table = The lua table, you want the value to be pushed in.
b) DataRef = The reference(!) of the DataRef you want to read out.
c) inIndex = The index where you want to start.
d) inMax = The number of values you want to access.
Reading out an integer DataRef array. If the DataRef is not readable as an integer array, or are
you using index values outside the range of the DataRef, the simulator may blow up without
a warning! The lua table will store the values with correct index seen from the world of XPlane. The first value can be indexed 0 (zero), if you start from the first entry of an array
DataRef. This is cool for C/C++ code, but uncool for Lua. So avoid ipairs() on tables made by
XPLMGetDatavi() commands.
10.1.5 table = XPLMGetDatavf( DataRef )

a) table = The lua table, you want the value to be pushed in.
b) DataRef = The reference(!) of the DataRef you want to read out.
c) inIndex = The index where you want to start.
d) inMax = The number of values you want to access.

Page 77 of 129

10.1

Reading classic functions

10

CLASSIC AND MODERN MODE

The same as above, but for float array DataRefs.

10.1.6 userdata variable = XPLMFindDataRef( DataRef Name )

a) userdata variable = The lua variable, you want the reference to be pushed in.
b) DataRef name = The name of the DataRef you want to know as a string.
The Lua variable will be filled with a »userdata«. This means, that you can’t do anything with
it’s value. It’s only needed for the XPLM functions.
10.1.7 datatype variable = XPLMGetDataRefTypes( DataRef reference )

a) datatype variable = The lua variable, you want the DataRef type to be pushed in.
b) DataRef reference = The reference of the DataRef you want to know it’s type.
The Lua variable will be filled with an integer, showing the type of the DataRef. The DataRefs
must be given by it’s reference, not by it’s name.

Page 78 of 129

10.1

Reading classic functions

10

CLASSIC AND MODERN MODE

This is a little example:

Forget the rest of the code and look at lines 8 to 25. They show how to handle an array DataRef
by reading and manipulation the battery. (In the more modern versions of X-Plane there is in
fact more than one battery! But most planes only interact with the first battery.)
As you can see in line 8, the following functions will read references instead of strings. It is not
possible to write:
t = XPLMGetDatavi("sim/cockpit/electrical/battery_array_on", 0, 4)
You will crash the simulator if you try it. To find the right argument, you first have to use
XPLMFindDataRef() - a very slow function. If you like performance, use it only as often as
needed.
In line no. 9 you force Lua to print batref, the variable holding the reference to the battery
DataRef. Lua says »FlyWithLua Error: nothing to say.« because a reference is strored
as a userdata, and can not be converted into a string, so the automatic converter results in nil
and the print() function can’t print it.

Page 79 of 129

10.2

Writing classic functions

10

CLASSIC AND MODERN MODE

10.2 Writing classic functions

To give values back to X-Plane, use one of these functions:
10.2.1 XPLMSetDatai( DataRef, variable or value)

a) DataRef = The reference(!) of the DataRef you want to write into.
b) variable or value = The lua variable, carrying the value you want to write, or a value
directly.
Use this for integer DataRefs.
10.2.2 XPLMSetDataf( DataRef, variable or value)

a) DataRef = The reference(!) of the DataRef you want to write into.
b) variable or value = The lua variable, carrying the value you want to write, or a value
directly.
Use this for float DataRefs.
10.2.3 XPLMSetDatad( DataRef, variable or value)

a) DataRef = The reference(!) of the DataRef you want to write into.
b) variable or value = The lua variable, carrying the value you want to write, or a value
directly.
Use this for double DataRefs.
10.2.4 XPLMSetDatavi( DataRef, table, inIndex, inMax )

a) DataRef = The reference(!) of the DataRef you want to write into.
b) table = The lua table, carrying the values you want to write, with correct indexes!
c) inIndex = The index where you want to start.
d) inMax = The number of values you want to access.
Use this for integer array DataRefs.

Page 80 of 129

11

THE LUA WAY TO ACCESS DATAREFS

10.2.5 XPLMSetDatavf( DataRef, table, inIndex, inMax )

a) DataRef = The reference(!) of the DataRef you want to write into.
b) table = The lua table, carrying the values you want to write, with correct indexes!
c) inIndex = The index where you want to start.
d) inMax = The number of values you want to access.
Use this for float array DataRefs.

11 The Lua way to access DataRefs
Classic code can be fine and super fast, but it is hard to read (and write). And all the methods to
access DataRefs we know until now aren’t good Lua code. The classic approach comes from the
SDK’s C code, so it fakes C-style to Lua. The modern style fakes a PLC and transfers DataRefs
to Lua variables. A clever code, but a little bit confusing when we want to access array DataRefs.
And it consumes more CPU power.
11.1 A magic metatable

The Lua way of life is to use a metatable. Metatables are one of the primary features making
Lua unique to other programming languages. FlyWithLua respects this of course, and provides
a magic metatable DATAREF_META_TABLE.
The magic metatable is defined in the file FlyWithLua.ini:
42
43
44
45

−− c r e a t e a magic m e t a t a b l e
DATAREF_META_TABLE = {}
DATAREF_META_TABLE . _ _ i n d e x = f u n c t i o n ( t , key ) r e t u r n p e e k ( t . r e f e r e n c e , t . r e f t y p e , key )
end
DATAREF_META_TABLE . _ _ n e w i n d e x = f u n c t i o n ( t , key , v a l u e ) poke ( t . r e f e r e n c e , t . r e f t y p e ,
key , v a l u e ) end

There are two undocumented functions in this metatable, peek() and poke(). Don’t care about
them. You do not need these functions, if you want to write a Lua-style script.
More important is, how the metatable works. It expects two values, reference and reftype as
elements of the table it is attached to.
Let’s create an empty table, add the elements needed by the metatable and attach the metatable
to the table. In this example, we will access the well known battery DataRef.
1
2
3
4

b a t t e r y = {}
b a t t e r y . r e f e r e n c e = XPLMFindDataRef ( " sim / c o c k p i t / e l e c t r i c a l / b a t t e r y _ a r r a y _ o n " )
b a t t e r y . r e f t y p e = XPLMGetDataRefTypes ( b a t t e r y . r e f e r e n c e )
s e t m e t a t a b l e ( b a t t e r y , DATAREF_META_TABLE )

Page 81 of 129

11.1

A magic metatable

11

THE LUA WAY TO ACCESS DATAREFS

Now we test the code (write through XSquawkBox’s input line).
>print( battery[0] )
Lua takes a look inside the table battery, searching for an element indexed with 0. The table
itself does not provide an element with this index.
Lua knows, that a metatable is attached to the table battery, so it looks into the metatable for
an element with the given index.
As there is no element DATAREF_META_TABLE[0], Lua looks for an element __index inside the
metatable. An element __index can be found as a function, and Lua now calls it this way:
DATAREF_META_TABLE.__index( battery, 0 )
And the function finally returns:
peek( battery.reference, battery.reftype, 0 )
This is resolved to 0, if the first battery is off, or to 1 if it is on.
Because of peek() and poke() ignoring the index, if the DataRef points to a single value instead
of an array, you can do the same magic access with all DataRefs X-Plane provides. The only
circumstance is to give a dummy index of 0 (zero) to all non-array DataRefs.
And if you give an index to a string DataRef, it will begin with the character at the index position
(starting at position 0, not 1).
As peek() and poke() are C-style functions, all indexes will start at 0 (zero), not 1 (like Lua
starts array indexes). This behavior was implemented, because of X-Plane’s DataRefs will always use 0 for the first index.
To shorten the code, FlyWithLua provides a function to declare a magic table in one single line
of code:
11.1.1 table = dataref_table( DataRef )

a) table = The lua table, you want to contain your magic.
b) DataRef = The name of the DataRef as a string.
Creating a new magic table to access the given DataRef, auto detecting the type of the DataRef.
The function dataref_table() initializes a direct access to the DataRef. This causes a conflict
to the PLC8 behavior of FlyWithLua. As a consequence dataref_table() always forces the
script to be classic code.
Never use dataref() and dataref_table() together in the same script file!
8 See

section »Understanding PLCs« for more info.

Page 82 of 129

12

MANAGE YOUR JOYSTICKS

12 Manage your joysticks
FlyWithLua was made to replace the plugin Button2DataRef, a very popular plugin to manage
your button and axis assignments. You can completely replace it with FlyWithLua 2.0.
This section of the quick manual will show a step-by-step creating process of a joystick config
script.
12.1 Get a basic configuration

The first step is to load your most used plane into the simulator, click into the joystick configuration menu of X-Plane, and setup everything as you want it to be.
Then restart X-Plane (with the same plane). Every time X-Plane is shut down, it saves your last
settings in a preference file:
«place where you store the sim»/X-Plane 10/Output/preferences/X-Plane.prf
This file keeps all joystick settings for the next run in a non Lua friendly way:
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691

...
_joy_AXIS_use97 0
_joy_AXIS_use98 0
_joy_AXIS_use99 0
_joy_BUTN_use0 sim / a u t o p i l o t / f d i r _ o n
_joy_BUTN_use1 sim / none / none
_joy_BUTN_use2 sim / view / c h a s e
_joy_BUTN_use3 sim / view / c h a s e
_joy_BUTN_use4 sim / g e n e r a l / z o o m _ i n _ f a s t
_joy_BUTN_use5 sim / g e n e r a l / z o o m _ o u t _ f a s t
_joy_BUTN_use6 sim / none / none
...

You could copy&paste the values out of this code, but there is an easier way. FlyWithLua
translates X-Plane’s preferences saved inside the X-Plane.prf file into a Lua readable script
code. The code is written to a file named:
«sim storage»/X-Plane 10/Resources/plugins/FlyWithLua/initial_assingments.txt
And yes, it’s a »txt« file, not a script file, because it is made for copy&paste only.
You will find the lines above translated into:
12
13
14
15
16
17
18
19

...
clear_all_button_assignments ()
set_button_assignment ( (0∗40) +
set_button_assignment ( (0∗40) +
set_button_assignment ( (0∗40) +
set_button_assignment ( (0∗40) +
set_button_assignment ( (0∗40) +
...

0,
2,
3,
4,
5,

" sim / a u t o p i l o t / f d i r _ o n " )
" sim / view / c h a s e " )
" sim / view / c h a s e " )
" sim / g e n e r a l / z o o m _ i n _ f a s t " )
" sim / g e n e r a l / z o o m _ o u t _ f a s t " )

Page 83 of 129

12.2

Define your sticks

12

MANAGE YOUR JOYSTICKS

FlyWithLua ignores all lines defining axis or buttons to nothing. This is done by the two function
calls clear_all_axis_assignments() (in line 5) and clear_all_button_assignments().
This prevents you from coding 1600 button assignments and 100 axis assignments.
Write a new script file into the Scripts folder and fill it with a copy of the automatic generated
configuration code.
12.2 Define your sticks

As you can see, FlyWithLua has made all button numbers to mathematic exercises. Why that?
You can easily see that all your joysticks start with it’s first button numbered by a multiple of
40. FlyWithLua prepared the code to use a nice standard function of text editors: »replace«.
Go to the beginning of your configuration script and type in a line like this:
LeftHandSteeringStick = 0
Then use your editor to replace all »(0*40)« with »LeftHandSteeringStick«.
The result will look similar to this code:
12
13

...
LeftHandSteeringStick = 0

14
15
16
17
18
19
20
21

clear_all_button_assignments ()
set_button_assignment ( LeftHandSteeringStick
set_button_assignment ( LeftHandSteeringStick
set_button_assignment ( LeftHandSteeringStick
set_button_assignment ( LeftHandSteeringStick
set_button_assignment ( LeftHandSteeringStick
...

+
+
+
+
+

0,
2,
3,
4,
5,

" sim / a u t o p i l o t / f d i r _ o n " )
" sim / view / c h a s e " )
" sim / view / c h a s e " )
" sim / g e n e r a l / z o o m _ i n _ f a s t " )
" sim / g e n e r a l / z o o m _ o u t _ f a s t " )

Now you are prepared to buy a new USB device. If your stick in your left hand starts at button
number 160 after you plug in an other joystick device, you will only have to change one line in
your code (line 13 in the example above). This is very cool if you are tired of still reconfiguring
your setup, while all the other members of the LAN party starts flying.
12.3 Define type specific assignments

Next step is to define settings, where plane types other than your favorite one need to be reconfigured. If your most used plane is a C172, and you want to fly the MD902 Explorer and a Bell
206 too, define a »helicopter class«.
The helicopter needs all »little helpers« like nullzone, sensitivity or augment at value 0.0 - to
give maximum control into your hand.
And of course the throttle has to be replaced by a collective.

Page 84 of 129

12.4

134
135
136
137
138
139
140
141
142
143
144
145
146

Lua for cockpit builders

12

−− a l l h e l i c o p t e r w i l l g e t a u n i q u e s e t t i n g a s d e f a u l t
function set_helicopter_assignments ()
s e t _ a x i s _ a s s i g n m e n t (12 , " c o l l e c t i v e " , " normal " )
s e t ( " sim / j o y s t i c k / j o y s t i c k _ p i t c h _ n u l l z o n e " ,
s e t ( " sim / j o y s t i c k / j o y s t i c k _ r o l l _ n u l l z o n e " ,
s e t ( " sim / j o y s t i c k / j o y s t i c k _ h e a d i n g _ n u l l z o n e " ,
s e t ( " sim / j o y s t i c k / j o y s t i c k _ p i t c h _ a u g m e n t " ,
s e t ( " sim / j o y s t i c k / j o y s t i c k _ r o l l _ a u g m e n t " ,
s e t ( " sim / j o y s t i c k / j o y s t i c k _ h e a d i n g _ a u g m e n t " ,
s e t ( " sim / j o y s t i c k / j o y s t i c k _ p i t c h _ s e n s i t i v i t y " ,
s e t ( " sim / j o y s t i c k / j o y s t i c k _ r o l l _ s e n s i t i v i t y " ,
s e t ( " sim / j o y s t i c k / j o y s t i c k _ h e a d i n g _ s e n s i t i v i t y " ,
end

0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0

MANAGE YOUR JOYSTICKS

)
)
)
)
)
)
)
)
)

After these lines of code, you can bind individual Helicopters (or Planes) to your aircraft types:
156
157
158
159

−− MD902 E x p l o r e r ( EXPL )
i f PLANE_ICAO == "EXPL" t h e n
set_helicopter_assignments ()
end

160
161
162
163
164

−− B e l l 206 D r e a m f o i l
i f PLANE_ICAO == " B06 " t h e n
set_helicopter_assignments ()
end

If a plane has no ICAO code, go into the Planemaker and correct it. Or you can use the predefined
variable PLANE_TAILNUMBER instead of PLANE_ICAO, if it is unique to this individual aircraft.
The work has to be done manually, there is no automatic way to define classes and bind aircrafts
to them. But it is easy to copy some lines and change the values. If you redefine a button
command, use the »button advanced« menu of X-Plane. You can copy&paste the command
string.
Finish!
From now on you will always start with the right setting in all aircrafts you cover by your
script.
12.4 Lua for cockpit builders

If you build a home cockpit like with Button2DataRef, you may want to bind buttons to DataRefs.
This is different to handle, if you are used to write B2D code, but not too complex.
FlyWithLua offers two functions, button() and last_button(). The function button()
needs the number of the button as its argument and delivers true if the button is pressed, else
you get false returned. The function last_buuton() gives the state one frame ago.
Let’s compare some code. First you get the old Button2DataRef code, followed by the Lua code,
doing exactly the same.

Page 85 of 129

12.4

Lua for cockpit builders

12

MANAGE YOUR JOYSTICKS

This is a typical configuration of a switch firing into a joystick button. If it is pressed (on), the
battery should be on, else it should be set to off:
#IF BUTTON 13 SWITCHES FROM 1 TO 1 SET sim/cockpit/electrical/battery_on TO 1
#IF BUTTON 13 SWITCHES FROM 0 TO 0 SET sim/cockpit/electrical/battery_on TO 0
1
2
3
4
5

i f b u t t o n ( 1 3 ) then
s e t ( " sim / c o c k p i t / e l e c t r i c a l / b a t t e r y _ o n " , 1 )
else
s e t ( " sim / c o c k p i t / e l e c t r i c a l / b a t t e r y _ o n " , 0 )
end

Next we want to release the parking brake if button 166 is released:
#IF BUTTON 166 SWITCHES FROM 1 TO 0 SET sim/flightmodel/controls/parkbrake TO 0
1
2
3

i f n o t b u t t o n ( 1 6 6 ) and l a s t _ b u t t o n ( 1 6 6 ) t h e n
s e t ( " sim / f l i g h t m o d e l / c o n t r o l s / p a r k b r a k e " , 0 )
end

Remember to put all your »button code« into a function called every frame. This can be done in
this way:
1
2
3
4
5

function parkbrake_button ()
i f n o t b u t t o n ( 1 6 6 ) and l a s t _ b u t t o n ( 1 6 6 ) t h e n
s e t ( " sim / f l i g h t m o d e l / c o n t r o l s / p a r k b r a k e " , 0 )
end
end

6
7

do_every_frame ( " parkbrake_button ( ) " )

Or shorter by using the »[[« and »]]« string delimiters:
1
2
3
4

do_every_frame ( [ [
i f n o t b u t t o n ( 1 6 6 ) and l a s t _ b u t t o n ( 1 6 6 ) t h e n
s e t ( " sim / f l i g h t m o d e l / c o n t r o l s / p a r k b r a k e " , 0 )
end ] ] )

It will produce an useless empty line of code inside the do_every_frame() routine, but this is
not a performance issue, as Lua will interpret a byte-code. The byte-code is compiled on the fly
and does not contain empty lines or comments slowing down the interpreter.
The next bad thing different to Button2DataRef is, that the function set() is much slower than
SET in B2D code. If you want the speed of Button2DataRef, define a DataRef first. A fast code
looks like this:
1
2
3
4
5

d a t a r e f ( " x p _ p a r k b r a k e " , " sim / f l i g h t m o d e l / c o n t r o l s / p a r k b r a k e " , " w r i t a b l e " )
do_every_frame ( [ [
i f n o t b u t t o n ( 1 6 6 ) and l a s t _ b u t t o n ( 1 6 6 ) t h e n
xp_parkbrake = 0
end ] ] )

Developers first law: Good code can prevent your simulator becoming a flip-book.
As a consequence never use set(), set_array() or get() in code looping every frame.

Page 86 of 129

13

UNDERSTANDING PLCS

13 Understanding PLCs
A programmable logic controller will do his work in endless cycling steps. These steps will
loop:
a) Read input values.
b) Do the calculations.
c) Write the output values.
The »modern part« of FlyWithLua works like a PLC. Let’s have a look into an example file:
1
2
3
4
5

d a t a r e f ( " x p _ b a t t e r y " , " sim / c o c k p i t / e l e c t r i c a l / b a t t e r y _ o n " , " w r i t a b l e " )
d a t a r e f ( " r o _ b a t t e r y " , " sim / c o c k p i t / e l e c t r i c a l / b a t t e r y _ o n " )
xp_battery = 1
print ( xp_battery )
print ( ro_battery )

You will get a warning in Log.txt, but the script will run. Turn off the battery and reload the
script. You will get:
1
0
The first printed result is what we expect. The battery was turned on, so after this we get a value
of 1 when querying the actual value of the battery. But is it really the actual value of the battery?
No, it is the actual value of the variable connected to the battery.
Remember the PLC steps. We are in the calculating step, and as a fact of this, the value isn’t
transfered from the variable xp_battery to the DataRef "sim/cockpit/electrical/battery_on"
yet. If all calculations are finished, FlyWithLua (who is acting like a PLC) goes to the writing
step, pushing all writable variable-DataRef bindings towards X-Plane. (After that it copies all
DataRefs to there variables, independent of the writable or readonly state, and comes to the next
calculation.)
So the second output is 0 and not 1, as the variable ro_battery was filled with 0 one PLC step
before (you turned off the battery before reloading the script).
If you do not »think as a PLC does«, you might get unexpected results from your own code.
There are three possible solution. The first is to learn to think like a PLC.

Page 87 of 129

13

UNDERSTANDING PLCS

But if you don’t like PLCs logic, you can use the functions get(), set() and set_array().
This is the second solution. Look at the screen shot some pages before. The program starts:
1
2
3

d a t a r e f ( " b a t t e r y " , " sim / c o c k p i t / e l e c t r i c a l / b a t t e r y _ o n " , " w r i t a b l e " )
s e t ( " sim / c o c k p i t / e l e c t r i c a l / b a t t e r y _ o n " , 1 )
print ( battery )

The result of this code is (reloading again with batteries off):
1
Hey! Is this real? Didn’t we say battery was filled with the value of 0 during the pulling step
before calculation?
Sure, we can try it out by adding a line of code:
1
2
3
4

d a t a r e f ( " b a t t e r y " , " sim / c o c k p i t / e l e c t r i c a l / b a t t e r y _ o n " , " w r i t a b l e " )
print ( battery )
s e t ( " sim / c o c k p i t / e l e c t r i c a l / b a t t e r y _ o n " , 1 )
print ( battery )

The output is now:
0
1
Strange! The reason to this behavior is, that set() will freeze the calculation, force a push step,
does its own manipulation, forces a pull step and gets back to the calculation point, where it
freezes the code. This doesn’t even sounds complicated, it is enormous time consuming. So if
you are a friend of performance, use set() only in time-uncritical situations.
The same behavior is shown by get() and set_array().
Coming to the third solution to escape from PLC logic. You can write classic mode script files.
If you do all the XPLM voodoo on your own, everything goes directly from or to the simulator.
But you will have to handle references and types. And you will get no error handling from
FlyWithLua.
To be able to handle all three coding styles in a wildly mix of multiple script files, FlyWithLua
needs two functions to switch his mode, begin_classic_mode() and end_classic_mode().
Please do not care about these two functions in your scripts. Just write script files who use only
one mode, a style mix of dataref() and get()/set() (modern mode), or clean XPLM based
code (classic mode). FlyWithLua will automatically insert the functions to change the mode if
needed. You may check this by writing a debug file to disk.
As switching between modes will consume CPU, sort your scripts. You can start all modern style
scripts with an uppercase letter and all classic style scripts with a lowercase letter. This will force
only one switch, the minimum if you use both styles. Or name scripts written in one style like a
lock and key service in a telephone directory (»AAAAAA_my_lttle_script.lua«).

Page 88 of 129

14

BASIC KNOWLEDGE ABOUT DATAREFS

14 Basic knowledge about DataRefs
If you are unfamiliar to DataRefs, you should read this section, if you already know everything
about DataRefs, you can skip it.
DataRefs are the main connection to X-Plane’s bowels. Most of them are writable, giving you
an enormous feature to tweak the simulator. But you need to know how they work and how to
access them.
14.1 What are DataRefs?

As your Lua scripts uses global variables, X-Plane itself has it’s own »variables«. But plugins
can’t see them, as they are not published to the plugins in a direct way. The plugin SDK/API
offers C/C++ code to access the »inner heart« of X-Plane by DataRefs.
Definition: A DataRef is a reference to a place in memory, where X-Plane stores a special
value. Each DataRef consists of a »folder/file-type« string giving the DataRef it’s name and the
reference itself.

14.2 Find the right DataRefs

If you want to find a DataRef to be used by your script, first take a look onto this site:
http://www.xsquawkbox.net/xpsdk/docs/DataRefs.html
This is the official website representing all DataRefs X-Plane offers. Always check this site and
use the search function of your web browser to look out for a good DataRef to use.
If you found an useful DataRef, do not stop your search. Sometimes there are more than one
DataRefs pointing to the same (logical) value. For example there is a DataRef »sim/cockpit/
electrical/battery_on«. This DataRefs allows you to turn on/off the battery. But there is
another DataRef »sim/cockpit/electrical/battery_array_on«.
The first DataRef only points to the first battery of the aircraft, but the second DataRef points to
an array of up to eight batteries. Most aircrafts will only simulate one battery, so it’s enough to
control it by the first DataRef. If an aircraft uses more than one battery, your script may result in
mysterious behavior.
Take a look onto the columns of the official DataRef website. The third column shown in what
version of X-Plane the DataRef is present. If you look onto the example above, you can see that
all planes since X-Plane 6.60 will provide access to only one main battery, but since version 8.20
there are up to eight batteries.

Page 89 of 129

14.3

Accessing DataRefs

14

BASIC KNOWLEDGE ABOUT DATAREFS

If you read out the value behind »sim/cockpit/misc/has_radar« using X-Plane 9.70, and
you send it to a friend using X-Plane 10.10r3, he might be surprised by the beauty of your
code.
14.3 Accessing DataRefs

A very important issue is, that the value in memory the DataRef points to, has a special byte
structure. The DataRef itself only points to the first byte, no matter what structure (or length)
the value has. It is your part to access the value the right way.
You can see the byte structure in the second column of the official DataRef list. If you find only
int, float or double, it is a single value behind the DataRef. If there are brackets behind the
type, it is an array of this type.
Only look into the second column to examine the type, not in the name of the DataRef. For example »sim/cockpit/electrical/battery_array_on« is an array of eight integer values, but
»sim/weather/cloud_type[2]« is only one single integer value, not an array of 2 values.
If you want access to a DataRef, you will first have to find out the reference. Use the function
XPLMFindDataRef() to get the reference. For example:
battery_ref = XPLMFindDataRef("sim/cockpit/electrical/battery_array_on")
Now you have the reference address stored in a variable named battery_ref. If you want to
turn on the third battery, you must access the value stored behind the DataRef like this:
1
2

−− f i n d o u t t h e r e f e r e n c e
b a t t e r y _ r e f = XPLMFindDataRef ( " sim / c o c k p i t / e l e c t r i c a l / b a t t e r y _ a r r a y _ o n " )

3
4
5

−− f i l l a t a b l e w i t h t h e v a l u e s f r o m t h e D a t a R e f
b a t t e r y _ a r r a y = XPLMGetDatavi ( b a t t e r y _ r e f , 0 , 8 )

6
7
8

−− c h a n g e t h e v a l u e r e p r e s e n t i n g t h e t h i r d b a t t e r y
battery_array [2] = 1

9
10
11

−− w r i t e t h e v a l u e s b a c k t o X−P l a n e
XPLMSetDatavi ( b a t t e r y _ r e f , b a t t e r y _ a r r a y , 0 , 8 )

In this code, you change battery_array[2] to turn on the third battery. All of X-Plane’s arrays
start at level 0 (like C/C++ does), not level 1 (like Lua does). The last value is battery_array[7].
In the functions XPLMGetDatavi() and XPLMSetDatavi() your arguments are »0, 8«, you start
at position 0 and get/set 8 values.
You can get all batteries into one table, do your changes to them, and at the last step write them
all back to X-Plane. Between getting and setting the values can be as much of code as you like.
But you do not need to get/set them all. If you only want to access to the third value, write a
code like this instead:

Page 90 of 129

14.4

1
2

Observe the DataRef

14

BASIC KNOWLEDGE ABOUT DATAREFS

−− f i n d o u t t h e r e f e r e n c e
b a t t e r y _ r e f = XPLMFindDataRef ( " sim / c o c k p i t / e l e c t r i c a l / b a t t e r y _ a r r a y _ o n " )

3
4
5

−− f i l l a t a b l e w i t h t h e v a l u e s f r o m t h e D a t a R e f
b a t t e r y _ a r r a y = XPLMGetDatavi ( b a t t e r y _ r e f , 2 , 1 )

6
7
8

−− c h a n g e t h e v a l u e r e p r e s e n t i n g t h e t h i r d b a t t e r y
battery_array [2] = 1

9
10
11

−− w r i t e t h e v a l u e s b a c k t o X−P l a n e
XPLMSetDatavi ( b a t t e r y _ r e f , b a t t e r y _ a r r a y , 2 , 1 )

Keep in mind that you still use a table, even if you want to access a single value. If the DataRef
points to an array, you must use the »array-function«.
If you use the modern code to access, FlyWithLua will always translate into single values. The
same code written in modern style will look like this:
1
2

−− d e f i n e t h e c o n n e c t i o n t o t h e t h i r d b a t t e r y
d a t a r e f ( " t h i r d _ b a t t e r y _ o n " , " sim / c o c k p i t / e l e c t r i c a l / b a t t e r y _ a r r a y _ o n " , " w r i t a b l e " , 2 )

3
4
5

−− c h a n g e t h e v a l u e o f t h e t h i r d b a t t e r y
third_battery_on = 1

The modern code style is shorter, but it is impossible to get/set complete arrays at once to/from
a Lua table.
14.4 Observe the DataRef

You should observe the behavior of a DataRef with the tool DataRef Editor. Sometimes a
DataRef (to be exact: the value behind it) will not behave as you aspect it.
Let’s have an example. You want to turn on the carb heat if there is ice in the engine. Your code
is this:
1
2

d a t a r e f ( " c a r b _ h e a t " , " sim / c o c k p i t 2 / e n g i n e / a c t u a t o r s / c a r b _ h e a t _ r a t i o " , " w r i t a b l e " , 0 )
d a t a r e f ( " i c i n g " , " sim / f l i g h t m o d e l / e n g i n e / ENGN_crbice " , " r e a d o n l y " )

3
4
5
6
7
8
9
10
11

function automatic_carb_heat ()
−− i f c a r b i s i c i n g t h e n s w i t c h h e a t on
i f ( i c i n g == 1 ) t h e n
carb_heat = 1
else
carb_heat = 0
end
end

Everything seems to be fine, FlyWithLua didn’t produce an error message and all other stuff
works well. Only your function automatic_carb_heat() will not react to ice inside the engine. Let’s observe the value of sim/flightmodel/engine/ENGN_crbice with the DataRef
Editor.

Page 91 of 129

14.4

Observe the DataRef

14

BASIC KNOWLEDGE ABOUT DATAREFS

Your code expects an integer value (yes = 1, no = 0), like the third_battery_on in the example
above. But sim/flightmodel/engine/ENGN_crbice is an array of float values, representing
a ratio of icing. The values start at zero, but they will grow up slowly. Before they reach a value
of 1.0, your plane usually crashed into ground.
If you absolutely dislike ice in your engine, change the code to:
1
2

d a t a r e f ( " c a r b _ h e a t " , " sim / c o c k p i t 2 / e n g i n e / a c t u a t o r s / c a r b _ h e a t _ r a t i o " , " w r i t a b l e " , 0 )
d a t a r e f ( " i c i n g " , " sim / f l i g h t m o d e l / e n g i n e / ENGN_crbice " , " r e a d o n l y " )

3
4
5
6
7
8
9
10
11

function automatic_carb_heat ()
−− i f c a r b i s i c i n g t h e n s w i t c h h e a t on
i f ( i c i n g > 0) then
carb_heat = 1
else
carb_heat = 0
end
end

As the value for the carb heat is a ratio too, but you are firing all or nothing, you may be too power
consuming. In times fuel gets more and more expansive, it might be better to give more power
to the carb heat, if there is more ice in the engine. Let your fantasy create a nice mathematic
model for the relationship level of ice —> level of carb heat.
1
2

d a t a r e f ( " c a r b _ h e a t " , " sim / c o c k p i t 2 / e n g i n e / a c t u a t o r s / c a r b _ h e a t _ r a t i o " , " w r i t a b l e " , 0 )
d a t a r e f ( " i c i n g " , " sim / f l i g h t m o d e l / e n g i n e / ENGN_crbice " , " r e a d o n l y " )

3
4
5
6
7
8
9
10
11

function automatic_carb_heat ()
−− i f c a r b i s i c i n g t h e n s w i t c h h e a t on
i f ( i c i n g > 0) then
carb_heat = 0.25 + icing ∗ 3/4
else
carb_heat = 0
end
end

Now you are using all benefits of float ratio values. The world is more than black/white, there
are nearly9 unlimited shades of gray.

9 As

a C/C++ float value is stored into a limited number of bytes, it represents a collection of discrete values.

Page 92 of 129

15

TAKE LUA INTO CONSIDERATION

15 Take Lua into consideration
There are some specials Lua offer, a script developer needs to know. In this section, we will show
some common mistakes/problems in scripting. If you are familiar with Lua, skip this section.
We will write an example file, not included in the FlyWithLua package. To follow this text, turn
on X-Plane and start a text editor. Then copy&paste the examples and see how X-Plane reacts.
15.1 Strings inside of strings

Let’s start with a typical script. You make a script printing out the solution of the universe.
1
2

xyz = 42
d o _ e v e r y _ d r a w ( " d r a w _ s t r i n g ( 5 0 , 5 0 0 , s t r i n g . f o r m a t ( " The s o l u t i o n i s %i " , xyz ) ) " )

The script seems to be ok, but FlyWithLua reacts like this (lines copied from Log.txt):
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146

F l y W i t h L u a I n f o : Lua e n g i n e ( r e ) s t a r t e d . LUA_RUN = 2 , SDK_VERSION = 2 1 0 , XPLANE_VERSION
= 1 0 1 0 1 , XPLANE_LANGUAGE = German and XPLANE_HOSTID = 1
F l y W i t h L u a : Load i n i f i l e .
F l y W i t h L u a : S e a r c h i n g f o r Lua s c r i p t f i l e s
F l y W i t h L u a : S o r t i n g Lua s c r i p t f i l e s
F l y W i t h L u a : S t a r t l o a d i n g s c r i p t f i l e R e s o u r c e s / p l u g i n s / F l y W i t h L u a / S c r i p t s / ALPHA . l u a
F l y W i t h L u a I n f o : No c l a s s i c commands f o u n d i n s i d e t h e f i l e .
F l y W i t h L u a : Lua h a s c r a s h e d , c a n ’ t e x e c u t e s c r i p t f i l e : R e s o u r c e s / p l u g i n s / F l y W i t h L u a /
S c r i p t s / ALPHA . l u a
F l y W i t h L u a : E r r o r l o a d i n g s c r i p t f i l e R e s o u r c e s / p l u g i n s / F l y W i t h L u a / S c r i p t s / ALPHA . l u a
F l y W i t h L u a Debug I n f o : The Lua s t a c k c o n t a i n s t h e f o l l o w i n g e l e m e n t s :
R e s o u r c e s / p l u g i n s / F l y W i t h L u a / S c r i p t s / ALPHA . l u a : 2 : ’ ) ’ e x p e c t e d n e a r ’ The ’
F l y W i t h L u a Debug I n f o : Debug f i l e w r i t t e n t o "< >/ FlyWithLua_Debug . t x t " .

Lua crashes! The reason is, that you put a string into a string the wrong way. The reason is not,
that you forgot a closing bracket. Always think twice when reading an error message!
A string can be set between the char »"« (double quotation), but you can also use »’« (single
quotation). This can set an inner string into an outer string.
The correct script looks like this:
1
2

xyz = 42
d o _ e v e r y _ d r a w ( ’ d r a w _ s t r i n g ( 5 0 , 5 0 0 , s t r i n g . f o r m a t ( " The s o l u t i o n i s %i " , xyz ) ) ’ )

Or you can write it this way:
1
2

xyz = 42
d o _ e v e r y _ d r a w ( " d r a w _ s t r i n g ( 5 0 , 5 0 0 , s t r i n g . f o r m a t ( ’ The s o l u t i o n i s %i ’ , xyz ) ) " )

Page 93 of 129

15.2

Multiple line strings

15

TAKE LUA INTO CONSIDERATION

15.2 Multiple line strings

If you want to declare a string over more than one line, you must use the delimiters »[[« (at the
beginning) and »]]« (at the end). This can look like:
1
2
3

xyz = 42
d o _ e v e r y _ d r a w ( [ [ d r a w _ s t r i n g ( 5 0 , 5 2 0 , " T h i s i s a l l you n e e d t o know : " )
d r a w _ s t r i n g ( 5 0 , 5 0 0 , s t r i n g . f o r m a t ( " The s o l u t i o n i s %i " , xyz ) ) ] ] )

There are a lot of more tricks handling strings. Please take a look into the official Lua 5.2
manual.
15.3 Global or local variables?

We will now name the script from above to ALPHA.lua and write a second script named BETA.lua:
1

xyz = 17

2
3
4
5

function beta_print_xyz ()
d r a w _ s t r i n g ( 5 0 , 4 5 0 , s t r i n g . f o r m a t ( "BETA : xyz = %i " , xyz ) )
end

6
7

do_every_draw ( " b e t a _ p r i n t _ x y z ( ) " )

This will produce no error message, all scripts run as they should, but the solution is now 17.
Why? It is because the first line of BETA.lua will overwrite variable xyz first initialized in line
1 of script ALPHA.lua (all scripts are compiled in alphabetical order). All variables used in Lua
are global variables, and every code can see and manipulate the variable!
But you can make a variable local. Make it local means, it can’t be seen from code outside of
the block it is declared in. To declare a local variable, just write »local« in front of the first use
of the variable. Change BETA.lua to:
1

l o c a l xyz = 17

2
3
4
5

function beta_print_xyz ()
d r a w _ s t r i n g ( 5 0 , 4 5 0 , s t r i n g . f o r m a t ( "BETA : xyz = %i " , xyz ) )
end

6
7

do_every_draw ( " b e t a _ p r i n t _ x y z ( ) " )

Now the solution switches back to 42. What happened here? The first line of BETA.lua declares
a local variable xyz. The global variable xyz from script ALPHA.lua still exists, but a local
variable will hide a global variable with an identical name. All code inside the active block will
now use the local variable instead of the global.
A function defined in the same block will now see the local variable xyz of the code block made
by the script file (a file is a block of code).

Page 94 of 129

15.4

Tables are tables

15

TAKE LUA INTO CONSIDERATION

Now we know how clever a script can be written, we will change the code of ALPHA.lua too.
This will avoid conflicts with scripts using a global variable named xyz, even if we do not have
a script like this at the moment. But we could get one from a friend or download one from the
Internet.
1
2
3

l o c a l xyz = 42
d o _ e v e r y _ d r a w ( [ [ d r a w _ s t r i n g ( 5 0 , 5 2 0 , " T h i s i s a l l you n e e d t o know : " )
d r a w _ s t r i n g ( 5 0 , 5 0 0 , s t r i n g . f o r m a t ( " The s o l u t i o n i s %i " , xyz ) ) ] ] )

Crash!
Was it not clever to declare every variable as local? What happened now?
The reason is, that the command do_every_draw() always creates a totally new block of
code, containing all strings from all scripts in it. This block is completely independent to all
other code you give to Lua. If you write a debug file, you can see this block inside the file
FlyWithLua_debug.txt in X-Plane’s main directory.
The functions do_sometimes(), do_often() and do-every_frame() behave the same way.
add_macro() creates two independent blocks of code and create_command() creates three
independent blocks of code, while add_ATC_macro() creates only one.
The trick in BETA.lua is, that we call a function beta_print_xyz() from the do_every_draw()
command block. Lua jumps into the function beta_print_xyz(). This is a jump into the block
automatically created by the file BETA.lua.
Important info: A jump from one block into another block (as made by a function call) changes
the view onto the variables (if local variables are declared)!
Conclusion: If you want to write code that does not make unwanted side-effects to other scripts,
keep all variables local and mask everything you want to be done continuously in a function.
Next conclusion: As the function DataRef() always creates a global variable, you must write
classic code, if you plan to share a script online. You will never know if the user, who downloaded your script, uses the same DataRef() binding as your script does. As long as you are the
only user of your script, you can do whatever you want. Just like in real life.
15.4 Tables are tables

If you use tables in Lua, you can’t use the name of the table as a variable. This code will fail
without a warning (it simply redefines the variable to hold a number instead of a table):
1
2

l o c a l b a t t e r y = d a t a r e f _ t a b l e ( " sim / c o c k p i t / e l e c t r i c a l / b a t t e r y _ o n " )
battery = 1

If you want to turn on the battery, use this code:
1
2

l o c a l b a t t e r y = d a t a r e f _ t a b l e ( " sim / c o c k p i t / e l e c t r i c a l / b a t t e r y _ o n " )
battery [0] = 1

Page 95 of 129

16

FLYWITHLUA 2.7.X ADDED NEW FEATURES

16 FlyWithLua 2.7.x Added New Features
Starting with version 2.7.0, FlyWithLua now supports creating native plugin windows. There
are two ways to use them:
graphics module: You can use the existing graphics module of FlyWithLua to draw into
the windows, see examples included in the "Scripts (disabled)" folder that start with
"floating_wnd".
imgui: FlyWithLua now supports creating imgui GUIs. imgui is an awesome 3rd party
GUI library that makes it really easy to create stunning GUIs. See the examples included
in the "Scripts (disabled)" folder that start with "imgui".
Why would you want to use these new capabilities instead of using existing GUI libraries written
in lua?
The windows can be moved and popped out to a native window
The performance is better because the GUI isn’t created by lua (for imgui windows)
Imgui is more powerful than the existing libraries - for example, you can load an image
file (even png and jpg) and use it as a background image or button or whatever...
Both window types automatically (!) work in VR
Here are a few teasing images to see what is now possible.

Page 96 of 129

16

FLYWITHLUA 2.7.X ADDED NEW FEATURES

Page 97 of 129

16

FLYWITHLUA 2.7.X ADDED NEW FEATURES

Page 98 of 129

16

FLYWITHLUA 2.7.X ADDED NEW FEATURES

The following functions don’t work with floating windows in VR anymore, no matter if using
imgui or FWL: do_every_frame, do_on_mouse_click.
Instead of using do_every_frame, you can register a drawing function that is called everytime XPlane draws the window. It gets passed the x and y coordinates of the window’s lower left corner
as absolute coordinates. This is required because FWL’s graphics functions take absolute screen
coordinates and you have to make sure that you actually draw into the window. For example,
if you pass (0, 0) as coordinates to a lua function that draws a dot, the pixel would always be
in the lower left of the screen because they are absolute coordinates. But if the window doesn’t
cover that part of the screen, the pixel wouldn’t be visible in the window. So if you want to put
the pixel in the lower left of the window, pass (x, y) as coordinates to the lua functions. If you
want a button on top of the window with a padding of 10px from the borders, you would draw a
rectangle with the first point at (x + 10, y + height - 10). I attached a sketch to visualize this. x
and y are passed as paramters to your drawing function by FlyWithLua and you must use them
to place your pixels inside the window.
And instead of do_on_mouse_click, you can register an onclick function with the floating window. That function is only called if the click actually happened inside the window, so it gets
passed relative coordinates already. So if the user clicks on the upper left of your button’s rectangle, it would get passed (10, height - 10). You would then have to set a flag to remember that
the user clicked somewhere so that you can then check this variable the next time the window is
drawn.
Using imgui, you don’t need to care about drawing the controls yourself or mapping the clicks
back to the controls. In fact, you don’t need to register an onclick function at all. imgui is an
immediate GUI, that means the controls don’t have any internal state. You can’t ask a checkbox
if it is currently checked and you can’t set a callback function to a button. They just have no
state at all. How does it work then? For imgui windows, you register a builder function. That
function is also called everytime the window is drawn. If you want to place a button, you just
call imgui.Button("My Button")
When you do that, imgui does not only draw the button, it also checks if the mouse button was
released over this area in the last frame. And if that’s the case, the Button function returns true!
It’s a little weird to get used to in the beginning, but all imgui functions actually return boolean
values to indicate whether they were just being used. So if you want to react on the button, you
just do something like this:
if imgui.Button("My Button") then
command_once("some x-plane command")
end
In the next frame, the mouse will not have been released over this button again, so the button
doesn’t return true in the next frame, resulting in your action being only called once as desired.
The same goes for other controls like sliders and checkboxes - they return a boolean to indicate
if you need to react on a change.

Page 99 of 129

16

FLYWITHLUA 2.7.X ADDED NEW FEATURES

Page 100 of 129

17

FLOATING WINDOWS

17 Floating Windows
Starting with version 2.7.0 NG we have floating windows that can be in 2d, popped out or in
VR. They are X-Plane 11 Window API style windows that can be created with Lua. There
are examples of these kind of windows in the "Scripts (disabled)" folder anf are prefaced with
"floating_wnd_".
17.1 demo_floating_wnd = float_wnd_create(800,450,1,false)

This is how you create a floating windows in lua.
"demo_floating_wnd" is the name of the handle of the window that is created.
The first two parameters specify the size of the window in boxels. Boxels are scalable pixels.If
the UI scale is set to 100% in the settings, a boxel equals a pixel. However, if the user sets the
UI scale to more than 100%, a boxel will be scaled to span multiple pixels.
The third parameter specifies the window decoration. The following decorations are possible:
0: "X-Plane will draw no decoration for your window, and apply no automatic click
handlers. The window will not stop click from passing through its bounds. This is
suitable for "windows" which request, say, the full screen bounds, then only draw in
a small portion of the available area."
1: "The default decoration for "native" windows, like the map. Provides a solid background, as well as click handlers for resizing and dragging the window."
2: "X-Plane will draw no decoration for your window, nor will it provide resize handlers for your window edges, but it will stop clicks from passing through your windows bounds."
3: "Like 2, but with resizing; X-Plane will draw no decoration for your window, but
it will stop clicks from passing through your windows bounds, and provide automatic
mouse handlers for resizing."
The last parameter configures whether you want to use imgui for the floating window. The return
value is a handle to the window that can be used to configure additional things.
17.2 float_wnd_set_title(demo_floating_wnd, "floating window Demo")

This function sets the title of the window if it has a decoration.
The first parameter must be a handle to the window previously created with the float_wind_create.
The second parameter is the title of the window.

Page 101 of 129

17.3

float_wnd_set_position(demo_floating_wnd, 775, 650)

17

FLOATING WINDOWS

17.3 float_wnd_set_position(demo_floating_wnd, 775, 650)

This function sets the initial position of the window.
The first parameter must be a handle to a window previously created with float_wnd_create.
The second and third parameters set the initial position of the window.
17.4 float_wnd_set_ondraw(demo_floating_wnd, "on_draw_floating_window")

This function sets the name of the ondraw function.
The first parameter must be a handle to a window previously created with float_wnd_create.
The second parameter sets the name of the ondraw function.
17.5 float_wnd_set_onclick(demo_floating_wnd, "on_click_floating_window")

This function sets the name of the onclick function.
The first parameter must be a handle to a window previously created with float_wnd_create.
The second parameter sets the name of the onclick function.
17.6 float_wnd_set_onclose(demo_floating_wnd, "on_close_floating_window")

This function sets the name of the onclose function.
The first parameter must be a handle to a window previously created with float_wnd_create.
The second parameter sets the name of the onclose function.
17.7 xplm_wnd = float_wnd_get_xplm_handle(demo_floating_wnd)

This function gets the xplm handle of the window created above to be used with ffi.
"xplm_wnd" is the name of the xplm handle of the window that was created.
The first parameter must be a handle to a window previously created with float_wnd_create.

Page 102 of 129

17.8

function on_draw_floating_window(demo_floating_wnd, x3,
17 y3)
FLOATING WINDOWS

17.8 function on_draw_floating_window(demo_floating_wnd, x3, y3)

The first parameter must be a handle to a window previously created with float_wnd_create.
x and y are the origin of the window, i.e. the lower left
x increases to the right, y increases to the top
17.9 function on_click_floating_window(demo_floating_wnd, x3, y3)

The first parameter must be a handle to a window previously created with float_wnd_create.
x and y are relative from the origin of the window, i.e. the lower left
17.10 function on_close_floating_window(demo_floating_wnd)

When on_close it called, it is illegal to do anything with the wnd variable.
It is also not allowed to create new windows in on_close!
The first parameter must be a handle to a window previously created with float_wnd_create.

Page 103 of 129

17.11

is_popped = float_wnd_is_popped(fwl_wnd)

17

FLOATING WINDOWS

17.11 is_popped = float_wnd_is_popped(fwl_wnd)

"is_popped" is the name of the boolean to know if the created window is popped out.
The parameter must be a handle to a window previously created with float_wnd_create.
17.12 is_visible = float_wnd_get_visible(fwl_wnd)

"is_visable" is the name of the boolean to know if the created window is visable.
The parameter must be a handle to a window previously created with float_wnd_create.
17.13 is_front = float_wnd_is_front(fwl_wnd)

"is_front" is the name of the boolean to know if the created window is in front.
The parameter must be a handle to a window previously created with float_wnd_create.
17.14 is_vr = float_wnd_is_vr(fwl_wnd)

"is_vr" is the name of the boolean to know if the created window is in vr.
The parameter must be a handle to a window previously created with float_wnd_create.
17.15 function float_wnd_bring_to_front(fwl_wnd)

The function brings the created window to the front.
The parameter must be a handle to a window previously created with float_wnd_create.
17.16 function float_wnd_set_resizing_limits(fwl_wnd, minWidth, minHeight,
maxWidth, maxHeight)

The function sets the resizing limits for the created window.
The first parameter must be a handle to a window previously created with float_wnd_create.
The second parameter sets the minimum width for the created window.
The third parameter sets the minimum height for the created window.
The forth parameter sets the maximum width for the created window.
The fifth paramter sets the maximum height for the created window.

Page 104 of 129

17.17

function float_wnd_set_positioning_mode(fwl_wnd, 1, -1)
17

FLOATING WINDOWS

17.17 function float_wnd_set_positioning_mode(fwl_wnd, 1, -1)

This function sets the positioning mode of the created window.
The first parameter must be a handle to a window previously created with float_wnd_create.
The second parameter sets the policy for how X-Plane will position whe created window.
Here are the aviable values for the policy.
xplm_WindowPositionFree
xplm_WindowCenterOnMonitor
xplm_WindowFullScreenOnMonitor
xplm_WindowFullScreenOnAllMonitors
xplm_WindowPopOut
xplm_WindowVR

0
1
2
3
4
5

The thrid parameter is the monitor index.
17.18 function float_wnd_set_gravity(fwl_wnd, gLeft, gTop, gRight, gBottom)

A window’s "gravity" controls how the window shifts as the whole X-Plane window resizes. A
gravity of 1 means the window maintains its positioning relative to the right or top edges, 0 the
left/bottom, and 0.5 keeps it centered.
Default gravity is (0, 1, 0, 1), meaning your window will maintain its position relative to the top
left and will not change size as its containing window grows.
If you wanted, say, a window that sticks to the top of the screen (with a constant height), but
which grows to take the full width of the window, you would pass (0, 1, 1, 1). Because your left
and right edges would maintain their positioning relative to their respective edges of the screen,
the whole width of your window would change with the X-Plane window.
Only applies to modern windows. (Windows created using the deprecated XPLMCreateWindow(), or windows compiled against a pre-XPLM300 version of the SDK will simply get the
default gravity.)
The first parameter must be a handle to a window previously created with float_wnd_create.
The remaining parameters follow the discription above.

Page 105 of 129

17.19

function float_wnd_set_geometry(fwl_wnd, nLeft, nTop,17
nRight,
FLOATING
nBottom)WINDOWS

17.19 function float_wnd_set_geometry(fwl_wnd, nLeft, nTop, nRight, nBottom)

This routine allows you to set the position and size of a normal 2d window.
for floating window, equivalent to - void XPLMSetWindowGeometry(XPLMWindowID inWindowID, int inLeft, int inTop, int inRight, int inBottom))
The units and coordinate system match those of XPLMGetWindowGeometry(). That is, modern
windows use global desktop boxel coordinates, while legacy windows use pixels relative to the
main X-Plane display.
Note that this only applies to "floating" windows (that is, windows that are drawn within the
X-Plane simulation windows, rather than being "popped out" into their own first-class operating
system windows). To set the position of windows whose positioning mode is xplm_WindowPopOut,
you’ll need to instead use XPLMSetWindowGeometryOS().
The first parameter must be a handle to a window previously created with float_wnd_create.
The remaining parameters set position and size of the created window.
17.20 function float_wnd_set_geometry(fwl_wnd, pLeft, pTop, pRight, pBottom)

This routine allows you to set the position and size of a poped out or OS 2d window.
for OS window, equivalent to - void XPLMSetWindowGeometryOS(XPLMWindowID inWindowID, int inLeft, int inTop, int inRight, int inBottom)
This routine allows you to set the position and size, in operating system pixel coordinates, of a
popped out window (that is, a window whose positioning mode is xplm_WindowPopOut, which
exists outside the X-Plane simulation window, in its own first-class operating system window).
Note that you are responsible for ensuring both that your window is popped out (using XPLMWindowIsPoppedOut()) and that a monitor really exists at the OS coordinates you provide (using
XPLMGetAllMonitorBoundsOS()).
The first parameter must be a handle to a window previously created with float_wnd_create.
The remaining parameters set position and size of the created window.

Page 106 of 129

17.21

function float_wnd_set_geometry(fwl_wnd, vrWidth, vrHeight)
17 FLOATING WINDOWS

17.21 function float_wnd_set_geometry(fwl_wnd, vrWidth, vrHeight)

This routine allows you to set the size of a VR window.
for VR window, equivalent to - void XPLMSetWindowGeometryVR(XPLMWindowID inWindowID, int widthBoxels, int heightBoxels)
This routine allows you to set the size, in boxels, of a window in VR (that is, a window whose
positioning mode is xplm_WindowVR).
Note that you are responsible for ensuring your window is in VR (using XPLMWindowIsInVR()).
The first parameter must be a handle to a window previously created with float_wnd_create.
The remaining parameters sets the size of the created window increasing or decreasing from a
centered position.

Page 107 of 129

17.22

nwinLeft, nwinTop, nwinRight, nwinBottom = float_wnd_get_geometry(fwl_wnd)
17 FLOATING WINDOWS

17.22 nwinLeft, nwinTop, nwinRight, nwinBottom =
float_wnd_get_geometry(fwl_wnd)

This routine returns the position and size of a normal 2d window. The units and coordinate
system vary depending on the type of window you have.
for floating window, equivalent to - void XPLMGetWindowGeometry(XPLMWindowID inWindowID, int * outLeft, int * outTop, int * outRight, int * outBottom)
If this is a legacy window (one compiled against a pre-XPLM300 version of the SDK, or an
XPLM300 window that was not created using XPLMCreateWindowEx()), the units are pixels
relative to the main X-Plane display.
If, on the other hand, this is a new X-Plane 11-style window (compiled against the XPLM300
SDK and created using XPLMCreateWindowEx()), the units are global desktop boxels.
Pass NULL to not receive any paramter.
"nwinLeft" Name of variable for the left side of the created window.
"nwinTop" Name of variable for the top of the created window.
"nwinRight" Name of variable for the right side of the created window.
"nwinBottom" Name of variable for the bottom of the created window.
The first parameter must be a handle to a window previously created with float_wnd_create.

Page 108 of 129

17.23

pwinLeft, pwinTop, pwinRight, pwinBottom = float_wnd_get_geometry(fwl_wnd)
17 FLOATING WINDOWS

17.23 pwinLeft, pwinTop, pwinRight, pwinBottom =
float_wnd_get_geometry(fwl_wnd)

This routine returns the position and size of a poped out or OS window. The units and coordinate
system vary depending on the type of window you have.
for OS window, equivalent to - void XPLMGetWindowGeometryOS(XPLMWindowID inWindowID, int * outLeft, int * outTop, int * outRight, int * outBottom)
This routine allows you to set the position and size, in operating system pixel coordinates, of a
popped out window (that is, a window whose positioning mode is xplm_WindowPopOut, which
exists outside the X-Plane simulation window, in its own first-class operating system window).
Note that you are responsible for ensuring both that your window is popped out (using XPLMWindowIsPoppedOut()) and that a monitor really exists at the OS coordinates you provide (using
XPLMGetAllMonitorBoundsOS()).
"pwinLeft" Name of variable for the left side of the created window.
"pwinTop" Name of variable for the top of the created window.
"pwinRight" Name of variable for the right side of the created window.
"pwinBottom" Name of variable for the bottom of the created window.
The first parameter must be a handle to a window previously created with float_wnd_create.
17.24 vrwinWidth, vrwinHeight = float_wnd_get_geometry(fwl_wnd)

This routine returns the size of a VR window.
for VR window, equivalent to - void XPLMGetWindowGeometryVR(XPLMWindowID inWindowID, int * outWidthBoxels, int * outHeightBoxels)
Returns the width and height, in boxels, of a window in VR. Note that you are responsible for
ensuring your window is in VR (using XPLMWindowIsInVR()).
"vrWidth" Name of variable to set vr width of the created window.
"vrHeight" Name of variable to set vr height of the created window.
The first parameter must be a handle to a window previously created with float_wnd_create.

Page 109 of 129

17.25

msgx, msgy = XPLMGetMouseLocationGlobal()

17

FLOATING WINDOWS

17.25 msgx, msgy = XPLMGetMouseLocationGlobal()

Returns the current mouse location in global desktop boxels. Unlike XPLMGetMouseLocation(), the bottom left of the main X-Plane window is not guaranteed to be (0, 0)—instead, the
origin is the lower left of the entire global desktop space. In addition, this routine gives the real
mouse location when the mouse goes to X-Plane windows other than the primary display. Thus,
it can be used with both pop-out windows and secondary monitors.
This is the mouse location function to use with modern windows (i.e., those created by XPLMCreateWindowEx()).
Pass NULL to not receive info about either parameter.
"msgx" Name of variable to get global x mouse location of the created window.
"msgy" Name of variable to get global y mouse location of the created window.
17.26 ssWidth, ssHeight = XPLMGetScreenSize()

This routine returns the size of the main X-Plane OpenGL window in pixels. This number can
be used to get a rough idea of the amount of detail the user will be able to see when drawing in
3-d.
"ssWidth" Name of variable to get screen size width.
"ssHeight" Name of variable to get screen size height.

Page 110 of 129

17.27

bLeft, bTop, bRight, bBottom = XPLMGetScreenBoundsGlobal()
17 FLOATING WINDOWS

17.27 bLeft, bTop, bRight, bBottom = XPLMGetScreenBoundsGlobal()

This routine returns the bounds of the "global" X-Plane desktop, in boxels. Unlike the nonglobal version XPLMGetScreenSize(), this is multi-monitor aware. There are three primary
consequences of multimonitor awareness.
First, if the user is running X-Plane in full-screen on two or more monitors (typically configured
using one full-screen window per monitor), the global desktop will be sized to include all XPlane windows.
Second, the origin of the screen coordinates is not guaranteed to be (0, 0). Suppose the user has
two displays side-by-side, both running at 1080p. Suppose further that they’ve configured their
OS to make the left display their "primary" monitor, and that X-Plane is running in full-screen
on their right monitor only. In this case, the global desktop bounds would be the rectangle from
(1920, 0) to (3840, 1080). If the user later asked X-Plane to draw on their primary monitor as
well, the bounds would change to (0, 0) to (3840, 1080).
Finally, if the usable area of the virtual desktop is not a perfect rectangle (for instance, because
the monitors have different resolutions or because one monitor is configured in the operating
system to be above and to the right of the other), the global desktop will include any wasted
space. Thus, if you have two 1080p monitors, and monitor 2 is configured to have its bottom
left touch monitor 1’s upper right, your global desktop area would be the rectangle from (0, 0)
to (3840, 2160).
Note that popped-out windows (windows drawn in their own operating system windows, rather
than "floating" within X-Plane) are not included in these bounds.
"bLeft" Name of variable for the left bounds of the "global" X-Plane desktop, in boxels.
"bTop" Name of variable for the top bounds of the "global" X-Plane desktop, in boxels.
"bRight" Name of variable for the right bounds of the "global" X-Plane desktop, in boxels.
"bBottom" Name of variable for the bottom bounds of the "global" X-Plane desktop, in boxels.

Page 111 of 129

17.28

tOS = XPLMGetAllMonitorBoundsOS()

17

FLOATING WINDOWS

17.28 tOS = XPLMGetAllMonitorBoundsOS()

This routine immediately calls you back with the bounds (in pixels) of each monitor within
the operating system’s global desktop space. Note that unlike XPLMGetAllMonitorBoundsGlobal(), this may include monitors that have no X-Plane window on them.
Note that this function’s monitor indices match those provided by XPLMGetAllMonitorBoundsGlobal(), but the coordinates are different (since the X-Plane global desktop may not match the
operating system’s global desktop, and one X-Plane boxel may be larger than one pixel).
This function returns the following values in a lua multi-dimensional table (an element for each
monitor):
int MonitorIndex; int inLeft; int inTop; int inRight; int inBottom;
To access the values in FWL, use the following format: tOS[x].yyyy, where x = monitor number,
and yyyy is table member.
Example for monitor 1: tOS[1].inLeft; tOS[1].inBottom; monitor 2: tOS[2].inLeft; tOS[2].inBottom
17.29 tGB = XPLMGetAllMonitorBoundsGlobal()

This routine immediately calls you back with the bounds (in boxels) of each full-screen X-Plane
window within the X-Plane global desktop space. Note that if a monitor is *not* covered by an
X-Plane window, you cannot get its bounds this way. Likewise, monitors with only an X-Plane
window (not in full-screen mode) will not be included.
If X-Plane is running in full-screen and your monitors are of the same size and configured
contiguously in the OS, then the combined global bounds of all full-screen monitors will match
the total global desktop bounds, as returned by XPLMGetScreenBoundsGlobal(). (Of course, if
X-Plane is running in windowed mode, this will not be the case. Likewise, if you have differently
sized monitors, the global desktop space will include wasted space.)
Note that this function’s monitor indices match those provided by XPLMGetAllMonitorBoundsOS(), but the coordinates are different (since the X-Plane global desktop may not match the
operating system’s global desktop, and one X-Plane boxel may be larger than one pixel due to
150% or 200% scaling).
This function returns the following values in a lua multi-dimensional table (an element for each
monitor):
int MonitorIndex; int inLeft; int inTop; int inRight; int inBottom;
To access the values in FWL, use the following format: tOS[x].yyyy, where x = monitor number,
and yyyy is table member.
Example for monitor 1: tOS[1].inLeft; tOS[1].inBottom; monitor 2: tOS[2].inLeft; tOS[2].inBottom

Page 112 of 129

18

IMGUI WINDOWS

18 Imgui Windows
Starting with version 2.7.0 NG we have imgui windows that can be in 2d, popped out or in VR.
They are X-Plane 11 Window API style windows that use imgui widgets and can be created
with Lua. There are examples of these kind of windows in the "Scripts (disabled)" folder and
are prefaced with "imgui_".
18.1 demo_wnd = float_wnd_create(800, 450, 1, true)

The first two parameters specify the size of the window in boxels. Boxels are scalable pixes. If
the UI scale is set to 100% in the settings, a boxel equals a pixel. However, if the user sets the
UI scale to more than 100%, a boxel will be scaled to span multiple pixels.
The third parameter specifies the window decoration. The following decorations are possible:
0: "X-Plane will draw no decoration for your window, and apply no automatic click
handlers. The window will not stop click from passing through its bounds. This is
suitable for "windows" which request, say, the full screen bounds, then only draw in a
small portion of the available area."
1: "The default decoration for "native" windows, like the map. Provides a solid background, as well as click handlers for resizing and dragging the window."
2: "X-Plane will draw no decoration for your window, nor will it provide resize handlers for your window edges, but it will stop clicks from passing through your windows
bounds."
3: "Like 2, but with resizing; X-Plane will draw no decoration for your window, but
it will stop clicks from passing through your windows bounds, and provide automatic
mouse handlers for resizing."
The last parameter configures whether you want to use imgui for the floating window.
The return value is a handle to the window that can be used to configure additional things.
18.2 float_wnd_set_title(demo_wnd, "Demo Window")

This function sets the title of the window if it has a decoration.
The first parameter must be a handle to a window previously created with float_wnd_create.
The second parameter is the title of the window.

Page 113 of 129

18.3

float_wnd_set_position(demo_wnd, 775, 650)

18

IMGUI WINDOWS

18.3 float_wnd_set_position(demo_wnd, 775, 650)

This function sets the initial position of the window.
The first parameter must be a handle to a window previously created with float_wnd_create.
The second and third parameters set the initial position of the window.
18.4 float_wnd_set_imgui_builder(demo_wnd, "build_demo")

imgui GUIs are built each frame. You will need to supply a function that is called every frame.
The first parameter must be a handle to a window previously created with float_wnd_create.
The second parameter must be the name of a function. Note that unlike other function in FlyWithLua, you can only pass the name of a function here, not an arbitrary lua string. This function will be called for every frame while the window is visible, so you don’t need an additional
do_every_frame unless you also need to do things while the window is closed.
18.5 float_wnd_set_onclose(demo_wnd, "closed_demo")

If the window has a decoration with a close button (like decoration 1), you might need a way
to know when the users closes the window. This function can be used to setup a function to be
called when the user closes the window.
The first parameter must be a handle to a window previously created with float_wnd_create
and the second parameter must be the name of a function. Note that unlike other function in
FlyWithLua, you can only pass the name of a function here, not an arbitrary lua string. This
function will be called when the user closes the window. After the window is closed, its builder
function will not be called again and it is illegal to use the window handle variable returned by
float_wnd_create, e.g. it is illegal to set the window title after it was closed.

Page 114 of 129

18.6

image_id = float_wnd_load_image(SCRIPT_DIRECTORY .. "/imgui_demo.jpg")
18 IMGUI WINDOWS

18.6 image_id = float_wnd_load_image(SCRIPT_DIRECTORY ..
"/imgui_demo.jpg")

imgui supports drawing images, so let’s load one. The images must always be loaded globally
to make sure they are only loaded once per script!
imgui widgets have no state, that means we need to store states of checkboxes, radio buttons etc.
globally.
makeRed = false
sliderVal = 0
choice = 1
angle = 0
text = ""
18.7 function build_demo(wnd, x, y)

This function is called for every frame. Use this function to create your GUI. The first parameter
(wnd) is the handle of the window. It is the same handle as the one returned by float_wnd_create.
It is required if you have multiple windows that use the same builder function so you know
which of these windows is currently being built. The x and y parameters are the current position
of the window in OpenGL coordinates, i.e. the position of the lower left corner in global screen
coordinates. These coordinates are only needed for using the graphics module on top of the
imgui GUI. If you only use imgui, these coordinates are not required because imgui has its own
coordinate system inside the window.
18.8 function closed_demo(wnd)

This function is called when the user closes the window. Drawing or calling imgui functions is
not allowed in this function as the window is already destroyed.

Page 115 of 129

19

DEBUGGING

19 Debugging
To domesticate the beast is a hard job sometimes. If you are searching an error inside your code,
FlyWithLua gives you a nice little weapon. Just click the menu entry Write Debug file. It
writes a file FlyWithLua_debug.txt into X-Plane’s main directory. You may observe the file
with a text editor able to recognize changes.
Inside the file you will find the content of Lua’s stack, the list of DataRefs handled by the plugin
and the content of the internal tables used by the plugin.
The debug info will show all global variables too. They are shown as name plus value. The
debug info ends with a list of all global tables and functions. A lot of information to dive deep
into FlyWithLua’s bowels.
If this is still not enough, and you need to look into a local variable or need a continuous observation of a variable, write a debug code like this (debugging the example one section before):
1
2

d a t a r e f ( " c a r b _ h e a t " , " sim / c o c k p i t 2 / e n g i n e / a c t u a t o r s / c a r b _ h e a t _ r a t i o " , " w r i t a b l e " , 0 )
d a t a r e f ( " i c i n g " , " sim / f l i g h t m o d e l / e n g i n e / ENGN_crbice " , " r e a d o n l y " )

3
4
5
6

function automatic_carb_heat ()
−− debug t h e v a r i a b l e
m y _ d e b u g _ s t r i n g = s t r i n g . f o r m a t ( " b e f o r e : i c i n g = %f , c a r b _ h e a t = %f " , i c i n g ,
carb_heat )

7
8
9
10
11
12
13
14
15

−− i f c a r b i s i c i n g t h e n s w i t c h h e a t on
i f ( i c i n g == 1 ) t h e n
carb_heat = 1
else
carb_heat = 0
end
m y _ d e b u g _ s t r i n g = m y _ d e b u g _ s t r i n g . . s t r i n g . f o r m a t ( " ==> a f t e r : i c i n g = %f ,
c a r b _ h e a t = %f " , i c i n g , c a r b _ h e a t )
end

16
17

do_often ( " automatic_carb_heat () " )

18
19

d o _ e v e r y _ d r a w ( " i f m y _ d e b u g _ s t r i n g t h e n d r a w _ s t r i n g ( 2 0 , 2 0 , m y _ d e b u g _ s t r i n g ) end " )

This example is pretty overobserved, but it shows how to observe more than one variable more
than one time.
Please recognize the code in line 19. If you do not use the if statement, FlyWithLua will crash,
when the first drawing frame has nothing to draw. If you don’t like the if statement in the last
line, start the script with:
my_debug_string = "No values at the moment."
After you solved the problem, simply remove the debug code.

Page 116 of 129

20

INTEGRATE FOREIGN LIBRARIES

20 Integrate foreign libraries
FlyWithLua provides a lot of features and functions, but there may be some function missing,
and you want to integrate a foreign library filling the hole.
Some libraries are easy to integrate. All you have to do is, to place the related files into the
Modules folder. If you choose a binary file, it must be compiled with MinGW on Windows
or GnuCC on Linux or Macintosh. Windows binaries end with .dll, Linux and Macintosh
binaries end with .so (it is important on Linux, that you copy the files into the Modules folder,
FlyWithLua will not search in your Linux library path).
We will look at two libraries made by Gerald Franz, LuaXML and proteaAudio, to show the
integration on an example.
For the LuaXML library, we only need to download it and copy the files LuaXML.lua and
LuaXML_lib.dll (or LuaXML_lib.dll) from the downloaded ZIP archive into the Modules
folder.
To integrate the proteaAudio library, we do the same for the binary file (proAudioRt.dll or
proAudioRt.so), but we have to do something more.
Using the library in a script file will force you not only to load the module (with a code line
containing require("proAudioRt")). You will also have to initialize and close the sound
device. This can be done in a script for sure, but if multiple scripts use the same sound module
and each script opens and closes the sound device independent from the other scripts, your set
of scripts will fail.
To avoid a fail like this, FlyWithLua gives you two files in it’s main folder you can edit,
user.ini and user.exit.
During startup, the script user.ini will be executed. So fill this script with code like this:
1
2
3
4
5
6
7

−− l o a d t h e s o u n d l i b r a r y and i n i t i t
require ( " proAudioRt " )
i f proAudio . c r e a t e ( ) then
logMsg ( " F l y W i t h L u a I n f o : Sound e n g i n e i s r u n n i n g . " )
else
logMsg ( " F l y W i t h L u a E r r o r : Can ’ t i n i t t h e s o u n d l i b r a r y ! " )
end

And shut down the sound device inside the file user.exit:
1
2
3

−− s h o t down s o u n d e n g i n e
proAudio . d e s t r o y ( )
logMsg ( " F l y W i t h L u a I n f o : Sound e n g i n e i s down . " )

Now every script behaves like the sound library was »battery included« in FlyWithLua.
The LuaXML library is included into FlyWithLua. If you want to use proteaAudio, you will have
to integrate it as described. Two example files for proteaAudio are included into FlyWithLua, to
help you making the first steps with this library.

Page 117 of 129

21

STATICALLY LINKING LIB’S INTO FLYWITHLUA PLUGIN BINARY.

21 Statically linking lib’s into FlyWithLua plugin binary.
This is from the commit from Alexander Zhirov explaining the benifit of statically linking
lib’s.
This is the safest way to ensure that the binary module is both compiled and linked against
exactly the same version of LuaJIT as used by FlyWithLua.
The conventional method [1] of building and linking binary Lua modules does not work well
in case of FlyWithLua. Normally the host executable would provide a Lua implementation and
any binary Lua module is supposed to link against symbols exported from the host at runtime.
This is impossible in case of X-Plane and FlyWithLua because FWL is a dynamically loaded
binary itself. Moreover, it is most likely to be not the only plugin with Lua code (e.g. aircrafts
using XLua or SASL), so we must not export Lua symbols into public space to avoid messy
conflicts.
All and all, it is the safest for us to link whatever binary Lua modules we want to support
and resort onto dynamically loaded binaries only in a worst case (e.g. users adding their own
modules).
All those considerations, however, don’t impact normal, non-binary Lua modules, since linking
is no concern for them.
lua-users.org/wiki/BuildingModules

Page 118 of 129

24

SOL2

22 LuaXML
There is a example script "test xml library LuaXML.lua" and its helper "test.xml" found in the
"Resources/plugins/FlyWithLua/Scripts (disabled)" folder.
LuaXML - LuaRocks

23 Luasocket
There is a example script "test_luasocket.lua" found in the "Resources/plugins/FlyWithLua/Scripts
(disabled)" folder.
LuaSocket

24 Sol2
There is two example scripts "floating_wnd_reference_test.lua" and "imgui_hello_world.lua"
found in the "Resources/plugins/FlyWithLua/Scripts (disabled)" folder.
Sol2 GitHub

Page 119 of 129

25

SCRIPTS (QUARANTINE) FOLDER

25 Scripts (Quarantine) folder
To try to reduce the number of the red "Lua Stopped" posts we are using a new method to find
and quarantine bad scripts. When FlyWithLua starts it looks at each script to see if any syntax
or dataref issues and if it finds them it will move the script to the "Scripts (Quarantine)" folder.
If it finds at lease one it will say "bad fly with lua scripts have been quarantined look in Log dot
text file for more information" and put a information line on the top of the screen. It also adds
information to the Log.txt file in as much detail as FlyWithLua can find.
This is our first attempt at trying to find errors and we know that there are errors that will be
missed but in future versions will try to find more. We now have a common place that if we can
find them they will be put preventing FlyWithLua from stopping.
After FlyWithLua has been running for 20 seconds if it finds scripts in the "Scripts (Quarantine)"
folder it will say and display "Please check your quarantined scripts folder" to let you know that
some of your scripts have been quarantined and you need to find out why.
To help with this a new menu item called "Return all quarantined Lua scripts" moves the scripts
found in "Scripts (Quarantine)" folder to the "Scripts" folder after you have found the issues. I
would next turn on the "Show Dev Console" so you can see new entries in the Log.txt file. Then
click on the "Reload all Lua script files" and look to see if all the errors are gone.
A second menu item has been added for developers called "Disable moving bad scripts to Quarantine" allowing them to turn off this feature while developing scripts.

Page 120 of 129

26

FWL_PREFS.INI FILE

26 fwl_prefs.ini file
We have started to use iniReader so FlyWithLua can have a preference file. The preference file
allows the user change the default behavior of FlyWithLua. Currently there is only one parameter that you can change and that is the developer mode. If a line starts with a ; it will be ignored
and used as a comment.
;FlyWithLua Preference file
;
;All lines begining with a ; are comments
;
;William R Good
;
;DeveloperMode = 0 Disabeled = 1 Enabeled
DeveloperMode = 0
If you change the 0 to a 1 you will be in developer mode and will disable the (Quarantine) folder
functions. This will be this way until you change it back to the default of 0.

Page 121 of 129

27

THE NEW 64-BIT ARCHITECTURE

27 The new 64-bit architecture
Since X-Plane 10.20 the simulator can run in 64-bit. As the simulator integrates the plugins as
dynamic libraries, the plugins will also have to use 64-bit code. FlyWithLua can run under both
conditions, 32 and 64 bit. But you will sometimes have to write different code for 32 and 64
bit.
27.1 Architecture exclusive script loading

If you rename a script, and change it’s ending from .lua to .lua64, FlyWithLua will only load
this file, if it is running in 64-bit mode. If you rename it’s ending to .lua32, the script file will
only be loaded when running in 32-bit. Else the file will be ignored.
You can also use .Lua64, .LUA64, Lua32 or LUA32.
If you use the ending .lua, .Lua or .LUA, it will be loaded in 32-bit and 64-bit architecture. As
a script is usually architecture independent, the ending without the number should be the normal
case.
27.2 Checking architecture inside a script

You can read out the global variable SYSTEM_ARCHITECTURE. It contains a number, either 64 or
32. If you need different code, use this system variable together with an if statement.
27.3 64-bit DLLs

If you want to use a dynamic library, you can call the library with the require command. The
DLL’s name must end as »_64.dll« on Windows, »_64.so« on Mac or Linux, if it has to be
loaded in 64-bit.
If your script starts with a line like this:
1

r e q u i r e ( " LuaXML_lib " )

there must be two DLLs to make it running under 32-bit and 64-bit, »LuaXML_lib.dll« and
»LuaXML_lib_64.dll«. This is for Windows system, for Mac and Linux, you will have to
provide »LuaXML_lib.so« and »LuaXML_lib_64.so«.

Page 122 of 129

28

Q&A

28 Q&A
At the end of this little manual, I will answer to some popular questions.
28.1 My script doesn’t work. What can I do?
28.1.1 Check the debug info file and Log.txt

Take a look into the file Log.txt provided by X-Plane. The easy way is clicking on X-Plane’s
menu item »special—>show dev console«, the more complex way is to use a text editor or a
command line tool like tail. Search the end of the file Log.txt for error reports generated by
FlyWithLua.
If FlyWithLua provides error or warning messages while loading or executing your script, pass
the messages through your brain, take your conclusions and edit your script file to eliminate the
problem.
If Lua stops working, it will automatically write a debug file in X-Plane’s main directory called
FlyWithLua_debug.txt. This file will also help to understand what’s going wrong. If it wasn’t
generated automatically, force a generation by clicking on »Plugins—>FlyWithLua—>Write
Debug file«.
28.1.2 Check for conflicts to other scripts

If the analysis made above didn’t solve your problem, move all other scripts to the disabled
folder and restart Lua. If the problem disappears, you might have a conflict to other scripts.
Move the other scripts back to the active scripts folder one by one and restart Lua after each file
movement.
By this way, you will find out the scripts, who causes the conflict. Compare the code of all
scripts causing the error. In most cases you will use a variable with a global scope in more than
one script. Rename the variable in one of the scripts or make them local.
Do this only for »normal« variables, not for variables connected to DataRefs. If a DataRef is
connected to more than one variable, rename all variables of this DataRef to be unique. FlyWithLua prints a warning message into the Log.txt file, if a DataRef is connected to multiple
variables.
28.1.3 I really can’t solve it!

Then ask for assistance. Most X-Plane related forums in the Internet will provide a developer
corner.

Page 123 of 129

28.2

How to ask the developer of FlyWithLua for help?

28

Q&A

28.2 How to ask the developer of FlyWithLua for help?

If nobody can solve your problem, you may ask me for some help. Write a mail to:
carsten.lynker@gmail.com
Your mail should use the word »FlyWithLua« in it’s subject line and must have a meaningful
subject, otherwise it will be deleted without reading.
The body of your mail must describe your problem in detail. As I have no time for an endless Q&A ping-pong, a mail without a detailed report of your problem will move directly into
dev/null.
Attached to the mail, you must send the FlyWithLua_debug.txt file and all lines of your
Log.txt file starting with »FlyWithLua« (make a tail | grep on Mac or Linux or use mTail on
Windows). And of course attach your script.
If you are using foreign binary libraries — forget it. I will not execute foreign binaries on my
development system. If you use plain Lua modules in your script, not included to FlyWithLua,
attach them as well.
A reaction to a mail can take several days (or weeks if I am busy). Keep in mind that this is my
hobby, not my job.
28.3 Is the debug file privacy safe?

By default, yes. It will hide your VATSIM ID, your real name and (most important) your VATSIM password – as long as you only use the pre-defined variables to access XSquawkBox. If you
are using DataRef access to online plugins (an IVAO client or something alike), delete private
info manually before sending the file to friend, a forum or to me.
28.4 Where are the Splines?

Splines are a nice feature of Button2DataRef, but FlyWithLua does not provide spline functions.
Button2DataRef isn’t able to calculate math expressions. So you must use splines. In most cases
splines are slower than direct formulas.
If you want to script a relationship defined by data points, take a look on this website:
http://arachnoid.com/polysolve/index.html#The_Program
It will help you to find a low-order polynomial expression to calculate your relationship.
If you want to make a mixture spline, where half way of your input device divides the mixture
by 1/4 to 3/4, enter these data points into the website:

Page 124 of 129

28.5

Feature requests

28

Q&A

0 0
0.5 0.75
1 1
Click on the »Output Form« button to get a result like this:
1
2
3
4
5

Mode : n o r m a l x , y a n a l y s i s
Polynomial degree 2 , 3 x , y data pairs .
C o r r e l a t i o n c o e f f i c i e n t ( r ^2) = 1.0000000000000004
S t a n d a r d e r r o r = 4 . 7 4 2 8 7 4 8 4 0 2 6 7 5 4 7 e −16
C o e f f i c i e n t o u t p u t form : m a t h e m a t i c a l f u n c t i o n :

6
7
8
9

f ( x ) = −1.6653345369377348 e −016 ∗ x ^0
+ 2 . 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 7 e +000 ∗ x ^1
+ −1.0000000000000027 e +000 ∗ x ^2

10
11

C o p y r i g h t ( c ) 2 0 1 2 , P . L u t u s −− h t t p : / / a r a c h n o i d . com . A l l R i g h t s R e s e r v e d .

The value -1.6653345369377348e-016 represents nearly nothing, so your script can use a calculation like this:
y = 0*x^0 + 2*x^1 + (-1)*x^2
y = 2*x - x^2
28.5 Feature requests

If you need a feature FlyWithLua doesn’t provide, you can start your own trunk of development,
as this is allowed by the license we use10 . But please first try to ask, if we implement your
wish into the official FlyWithLua project. This can help to protect users getting confused by
thousands of different flavors of Lua Scripting plugins.
28.6 Can I store Lua files inside the aircraft’s folder?

Not by default. You should leave an aircraft as it is, to avoid surprising behavior when you (or
X-Plane) update the plane. But if you want to store all your joystick configuration inside the
aircraft’s folder, write a »loader« script into the script folder and fill it like this:
1

d o f i l e ( AIRCRAFT_PATH . . " m y _ j o y s t i c k _ c o n f i g u r a t i o n . l u a " )

Then this script will load the other script, but make sure that every plane you load has a file that
can be read. It can be empty, if you have no Lua code for that plane.

10 See

section »License« for detailed info.

Page 125 of 129

28.7

I want full access to X-Plane’s plugin SDK!

28

Q&A

28.7 I want full access to X-Plane’s plugin SDK!

The plugin SDK is a complete interface to X-Plane from Delphi, C or C++, but not from Lua.
FlyWithLua offers the most important functions of the plugin SDK for little scripts. But you
may want more.
The nice side effect choosing LuaJIT as the Lua engine of FlyWithLua is, that you can take
advantage of the FFI library. It allows to access every C-function from Lua. And you can
declare C-types to be used in Lua code. For a documentation of FFI see:
http://luajit.org/ext_ffi.html
Let’s make an example. Reloading the scenery is possible, even if there is no XPLMReloadScenery() function provided by FlyWithLua. We will create a macro doing the reload:
12
13
14

−− l o a d t h e XPLM l i b r a r y
local f f i = require ( " f f i " )
l o c a l XPLM = f f i . l o a d ( "XPLM" )

15
16
17

−− d e f i n e t h e XPLMReloadScenery ( ) C−f u n c t i o n t o be u s e d f r o m Lua
f f i . c d e f ( " v o i d XPLMReloadScenery ( v o i d ) " )

18
19
20
21
22
23

−− d e f i n e a g l o b a l f u n c t i o n ( macros can o n l y a c c e s s g l o b a l f u n c t i o n s )
function reload_scenery ()
XPLMSpeakString ( " P l e a s e w a i t , X−P l a n e i s r e l o a d i n g t h e s c e n e r y . Don ’ t p a n i c ! The
s i m u l a t o r w i l l f r e e z e f o r a moment . " )
XPLM . XPLMReloadScenery ( )
end

24
25
26

−− c r e a t e t h e macro
add_macro ( " R e l o a d t h e s c e n e r y " , " r e l o a d _ s c e n e r y ( ) " )

Other example files can be found in the Scripts (disabled) folder.
If you want to use the FFI access to the plugin SDK in more than one script, you can collect all
definitions of the C-functions in a Lua module and start your script with:
require "name of your module"

Page 126 of 129

28.8

Using Lua For Windows

28

Q&A

28.8 Using Lua For Windows

If you don’t like the extreme fast LuaJIT engine, and you are using Lua For Windows on a
Windows system, then you can replace the Lua engine of FlyWithLua. When you change the
engine, you will loose the libraries included by LuaJIT (FFI and Bit).
Doing the following steps changes the Lua engine of FlyWithLua. Every change on basic
binary files is not supported by the FlyWithLua developer team! If you get problems after
an engine change, solve it on your own or come back to the official FlyWithLua.
This has to be done:
a) Download Lua For Windows and run the Installer.
b) Delete the file FlyWithLua\lua51.dll in X-Plane’s plugin folder.
c) Go into the subfolder Lua\5.1\, of your just installed Lua For Windows.
d) Copy the files lua51.dll and lua5.1.dll into FlyWithLua, replacing the old lua51.dll.
e) Copy all files you find inside the Lua For Windows folder Lua\5.1\clibs into the FlyWithLua subfolder Modules.
That’s all. Now you are using the Lua interpreter provided by Lua For Windows, not the Just-InTime compiler LuaJIT. If you don’t have thousands of lines with Lua code, you will not »feel«
the difference in execution speed. But you now access an enormous pool of usable libraries like
Lua Socket.

Page 127 of 129

29

CREDITS

29 Credits
This plugin was made by Carsten Lynker (main developer, Windows code), Snagar (early Macintosh and Linux code), William B. Good (Macintosh and Linux code) and Ingo Alm (lector and
bughunter).
Starting with Carsten’s great plugin the following developers helped create and improve FlyWithLua NG. Folke Will (initial implementation of floating windows and imgui), Alexander
Zhirov (adding Luaxml and Luasocket to binary and adding the use of sol2), IanQ (added
more floating windows methods), William Good (updating this manual and other small improvements)
FlyWithLua uses source code
from HIDAPI, created by Alan Ott, Signal 11 Software,
from The LuaJIT Project, created by Mike Pall
and code snippets from Kein-Hong Man’s luahidapi.
FlyWithLua uses two library packages made by Gerald Franz, LuaXML and proteaAudio.
Graphic design of the logo by Alexandre Nakonechnyj, Copyright Âl’ 1998 Lua.org11 .
If you find a bug produced by the plugin, please email:
carsten.lynker@gmail.com
Happy landings!

11 For

more information about license and design of Lua see www.lua.org.

Page 128 of 129

30

LICENSE

30 License
Copyright (c) 2012 Carsten Lynker
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to
do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Page 129 of 129



Source Exif Data:
File Type                       : PDF
File Type Extension             : pdf
MIME Type                       : application/pdf
PDF Version                     : 1.5
Linearized                      : No
Page Count                      : 129
Page Mode                       : UseOutlines
Author                          : 
Title                           : FlyWithLua Quick Reference Manual
Subject                         : 
Creator                         : LaTeX with hyperref package
Producer                        : pdfTeX-1.40.16
Create Date                     : 2019:03:12 07:07:09-04:00
Modify Date                     : 2019:03:12 07:07:09-04:00
Trapped                         : False
PTEX Fullbanner                 : This is pdfTeX, Version 3.14159265-2.6-1.40.16 (TeX Live 2015/Debian) kpathsea version 6.2.1
EXIF Metadata provided by EXIF.tools

Navigation menu