XLua 2
Introduction
XLua is a lightweight implementation of the lua scripting language designed to run within X-Plane, providing access to the range of commands and datarefs offered. XLua2 is a considerably extended version, providing almost full access to the X-Plane SDK.
Comparison with XLua
XLua2 uses a different approach to the original XLua plugin. Instead of providing a small number of functions to exchange data with the simulator, it exposes the majority of the X-Plane SDK. Old-style data-access functions, while still supported for old scripts, can not be used in an XLua2 script. You are, however, free to mix and match XLua and XLua2 scripts within the same plugin, so if you are upgrading this can be done incrementally.
New UI Abilities
XLua 2 includes support for the well-known “DearImGui” interface design system, allowing simple but flexible UI elements to be added.
XPLM API Access
Almost the full XPLM API, as used in compiled plugins, can be used in XLua2. This means that the same capabilities and the same documentation may be shared across all languages. The SDK documentation is online at https://developer.x-plane.com/sdk/ .
Installation
The base requirements for XLua2 are the plugin itself, init.lua, the include directory, and a scripts directory. You should not use init.lua from XLua, it will not work correctly with XLua2.
The “include” directory contains reference files which define key values used by XPLM, and describe each of the functions provided by that logical module. For example, the “XPLMMap” module provides functions that allow you to manipulate the sim’s map window.
Upgrading an existing aircraft
The process for upgrading an existing XLua plugin is no different to normal installation. Don’t have two different copies of XLua at different versions – existing XLua scripts work with no changes.
System-level use
New for XLua2, it may be installed as a general system-level plugin under “Resources/plugins”. This may be used in addition to an aircraft-level copy. Installing at system level allows you to run XLua scripts which are not tied to a specific aircraft.
Getting Started
A good place to start would be to read the sample scripts under xplm_test, imgui_test and panel_gfx_test . These represent good coverage of all the available features, and show how to use the scripts in general as well as advanced usage.
Scripts are arranged in separate folders under the “scripts” directory. Within each sub-folder, the master script should be named the same as the folder, plus the “.lua” suffix. So the xplm_test script is called xplm_test.lua, inside the xplm_test folder.
Each folder may have other scripts if you wish to split your code into separate files, but only the one with the same name as the folder will initially be loaded. All files referenced by the master script in each folder must use the same API type – that is, you can’t require() a file which uses the XLua2 API from an old-style XLua file.
Version Selection
To specify that a given script should use the XLua2/XPLM API, the first line of the script should be exactly this:
--[[ XLua 2.0 ]]
Without this, the script will be interpreted as an old XLua script and limited to only those functions provided by the original XLua.
General Structure
Each top level XLua2 script is treated in a very similar way to a compiled plugin. It may define functions called XPluginStart, XPluginEnable, XPluginDisable and XPluginStop. These will be called as the script is loaded and enabled, and disabled and stopped. They are fully described in the XPLM developers guide at https://developer.x-plane.com/article/developing-plugins/ . Note that each of these functions is optional in an XLua2 script, unlike in a compiled plugin.
XPluginStart and XPluginEnable take no parameters, and must return a Boolean stating whether or not you wish the script to be loaded and enabled, respectively. XPluginDisable and XPluginStop take no parameters and must return no value. These are called when the script is disabled and stopped.
XPluginStart and XPluginStop will be called once only, when the script is first loaded and last unloaded. Use XPluginStart to create any resources you need to be available throughout the script’s lifetime. Always release those resources in XPluginStop.
XPluginEnable and XPluginDisable may be called repeatedly to allow suspension of the script without having to deallocate any resources each time.
XPluginReceiveMessage, if defined, allows your script to be notified of key events.
Per-frame callbacks
To have some lua code called for each frame, use the XPLMCreateFlightLoop API. This allows you to provide a function to be called, either before or after the flight model has run. After creating a flightloop callback, you would then schedule that callback using the XPLMScheduleFlightLoop API. This tells X-Plane that you wish the callback to be used, when, and how frequently. Use the minimum number of callbacks possible; if you need to run several different logical code sections each frame, for example, it is cleaner and more efficient to have a single flightloop callback which calls each logical section in turn rather than one callback each.
Logging
Output to the log is possible using lua’s native “print” function. Log lines are written to the normal “Log.txt” in X-Plane’s folder. Each line will be prefixed with a timestamp and the “I/LUA” tag. Don’t write general messages to the log per-frame unless you’re debugging.
Unsupported Features
Some features in the full SDK are not available to Lua:
- Shared data between plugins. This is currently incompatible with certain Lua requirements.
- Deprecated drawing and window functions. Use ImGui or PanelGraphics.
- Deprecated AI-aircraft drawing functions. Use Instances.
- Deprecated flight-loop functions. Use the newer versions.
- Not yet implemented.
- Not yet implemented.
- Certain file/path functions. Use native Lua functions along with other XPLM path functions.
General API Description
There are a few key differences to general Lua behaviour when using the XPLM APIs. This is necessary to keep the API usage the same across all languages.
0-based indexing
Any place in XPLM where an index number is required, the indices start with 0 instead of Lua’s normal 1-based indexing. For example, XPLMGetNthAircraftModel(0) would return the information for aircraft number 0 – the user’s aircraft.
Not fully managed
Any resource allocated using an XPLM function, typically called XPLMCreate… , must be manually destroyed when you are done with it. It will not be destroyed when the handle returned from the XPLMCreate… call goes out of scope. In particular, don’t call XPLMCreate continually at the start of a function, then use the thing created for the duration of that function; it will not be destroyed when the function exits and you will be creating one new copy per call.
Callbacks are used to handle task-specific customisations
Many XPLM functions will allow you to pass a function reference as one of the parameters. The function will be given parameters as described in the header file and XPLM documentation, and must return a value of the correct type.
Awareness of key events
A top-level function, XPReceiveMessage, is called whenever key events occur within the simulator or another plugin. You should use this function to be notified of any event of interest to you.
Migrating scripts from XLua
To upgrade an existing script to use the XLua2 API, first put the required comment as the first line:
--[[ XLua 2.0 ]]
Next, replace the old XLua functions that your script provided:
| aircraft_load() | XPluginReceiveMessage(), checking for the XPLM_MSG_PLANE_LOADED message. To duplicate original XLua behaviour, check for XPLM_MSG_AIRPORT_LOADED since this is where it used to be called. |
|---|---|
| aircraft_unload() | XPluginReceiveMessage(), checking for the XPLM_MSG_PLANE_UNLOADED message. You should probably also handle this during shutdown, either from XPluginDisable() or XPluginStop(). |
| flight_start() | XPluginReceiveMessage(), checking for the XPLM_MSG_AIRPORT_LOADED message. |
| flight_crash() | XPluginReceiveMessage(), checking for the XPLM_MSG_PLANE_CRASHED message. |
| **before_physics(), | |
| after_physics()** | Use one or more flight loops, created using XPLMCreateFlightLoop() and XPLMScheduleFlightLoop(). |
| after_replay() | No direct equivalent but can be detected using the “sim/time/is_in_replay” dataref in a flightloop callback. |
Replace any usage of XLua functions provided by init.lua:
| find_dataref() | XPLMFindDataRef(). Note that you must use separate functions to read the values unlike XLua |
|---|---|
| create_dataref() | XPLMRegisterDataAccessor() |
| find_command() | XPLMFindCommand() |
| create_command() | XPLMCreateCommand() |
| replace_command() | XPLMRegisterCommandHandler() |
| wrap_command() | XPLMRegisterCommandHandler() |
| filter_command() | XPLMRegisterCommandHandler() |
| receive_message() | XPLMReceiveMessage() |
| run_timer(), stop_timer(), is_timer_scheduled(), get_timer_remaining(), run_at_interval(), run_after_time() | Supported in XLua2 |
| isnan() | Supported in XLua2 |
Check that for each XPLM…Create or XPLM…Register call you use, ensure you have a matched XPLM…Destroy or XPLM…Unregister called at an appropriate time, typically in XPluginDisable or XPluginStop.