XLua Best Practices
This section only puts forth recommendations based on our experiences. These are not rules which are required by XLua; however, adopting these practices is recommended, even for the simplest projects. A good deal of the naming practices described below evolved from the frequent need for you to find your symbol (variables, tables and functions) names throughout your project, and using standardized protocols in your naming will give you hooks to search/find that kind of data you need to find.
Constant Names
- Use all caps for constant names.
MAX_SPEED = 100
Global Var Names
- Use prefix "g_" for global var names.
g_seconds_from_last = 0
Local Var Names
- Use prefix "l_" for local var names.
local l_loop_counter = 1
XP Dataref Names
- Use prefix "xdr_" to denote X-Plane dataref variables. You might create your own customized simulations to override X-Plane's simulations and your variables may have similiar names. Using 'xdr_' labels in your names helps you know where the values come from, either you or X-Plane.
xdr_sim_paused = find_dataref("sim/time/paused") -- xdr = "XplaneDataRef"
if xdr_bus_volts[0] > 14.0 then.... -- XPlane's bus volt value
XP Command Names
- Use prefix, xcmd_ for X-Plane Command variable names. (handles)
- For callback names associated with X-Plane commands, use xccb_ prefix and _[b,a,f]handler suffixes. Handler functions exist for custom commands, X-Plane commands and X-Plane datarefs. Using the prefix/suffix helps you distinguish what type your handler function is bound from the name of the function only. The more command callbacks you have, the more important this convention will become.
--PREFIX/SUFFIX when AUGMENTING XP COMMAND-----------------
function xccb_flaps_up_bhandler(phase, duration) -- use _bhandler suffix to mean "before xplane handler"
function xccb_flaps_up_ahandler(phase, duration) -- use _ahandler suffix to mean "after xplane handler"
function xccb_flaps_dn_fhandler() -- use _fhandler suffix to mean "a filter handler"
xcmd_flaps_up = wrap_command("sim/flight_controls/flaps_up", xccb_flaps_up_bhandler, xccb_flaps_up_ahandler)
--PREFIX/SUFFIX when REPLACING XP COMMAND-----------------
function xccb_flaps_dn_handler() -- use _handler suffix, since only one callback handler is used with "replace_command"
xcmd_flaps_dn = replace_command("sim/flight_controls/flaps_down", xccb_flaps_dn_handler)
Custom Dataref Names
- Use prefix "cdr_" in your custom dataref handle names. cdr = "CustomDataRef"
- For Custom Write Dataref callback names, use "cdr_" prefix and "_handler" suffix in your names for the reasons stated above.
cdr_window_animation_ratio = create_dataref("mycustom/window/animation_ratio", "number") --create custom dataref
-- The below var names illustrates how using 'cdr_' and 'xdr_' prefixes help you distinguish data sources from one
-- another. The more you customize, the higher likelihood you may override X-Plane's data and ***mimicking*** x-plane
-- dataref names is quite common.
cdr_bus_volts
xdr_bus_volts
-- BELOW: custom DR write handler showing prefix/suffix use.
-- The name of the function alone tells you this is a
-- write callback handler for the "door_handle_ratio" custom dataref.
cdr_door_handle_ratio_handler = function()
Custom Command Names
- Use prefix, ccmd_ to identify your custom command handle names.
- For custom command callbacks, use "ccb_" prefixes and "_handler" suffix labels with your callback function names, same reasons as above.
-- Custom Command Handler Function
ccb_toggle_avitab_position_handler = function()
-- Custom Command Declaration
ccmd_toggle_avitab_position = create_command("laminar/misc/toggle_avitab_position", ccb_toggle_avitab_position_handler)
Flight Loop Functions
For longer code blocks that need to run every flight loop, wrap that code into your own custom functions and add the suffix, "_FLCB" to the function name to remind you these are running every flight loop. THEN call these functions from one of XLua's physics callbacks, which of course runs every flight loop. This keeps the physics functions from becoming polluted with long blocks of code that can be difficult to interpret the longer it gets.
function hydraulics_FLCB()
-- do hydraulics stuff
end
function electrical_FLCB()
-- do electrical stuff
end
after_physics()
hydraulics_FLCB()
electrical_FLCB()
end
Comments
-
Simply put, use comments and explanations judiciously (all over the place) to remind yourself (and others) of how your script works. You will forget over time. Be verbose and clear. See Example Here
-
Use divider comment lines to separate logical code blocks. Sometimes its hard to see where a function ends. See XLua Template
-
Put a comment after the final end keyword of longer functions and blocks. Many nested end keywords can be tough to figure out which block they apply to. See example below.
g_some_table = {0, 1, 5.4, 12, 23.3}
--A divider comment line -------------------------------------
function does_alot_of_stuff()
for i, v in ipairs(g_some_table) do
if v == 0 then
print("next number in line is 1")
elseif v == 1 then
print("next number in line is 5.4")
else
for j = 1, 15, 1 do
if j == v then
print("we matched the whole number " .. v)
end
end -- of iterator j=1, 15
end -- of enumeration switch
end -- of g_some_table iterator
end -- of function 'does_alot_of_stuff'
Code Alignment
Code Alignment is a personal preference. Code that does similar things is easier to read when aligned in columns and grouped together. See XLua Example Template
--HARD TO READ (but works fine)--
g_myvar1=0
local l_myvariabl2="N234MA"
g_bobsvar3=3.23343
tomsfunction=function() end
local l_bus_state = false
xdr_running_time=find_dataref("sim/time/running_time")
--EASIER TO READ, and still works fine--
local l_bus_state = false
local l_myvariabl2 = "N234MA"
g_myvar1 = 0
g_bobsvar3 = 3.23343
tomsfunction = function() end
xdr_running_time = find_dataref("sim/time/running_time")
Variable Names
Be VERY descriptive when naming your variables and name them according to what they actually do. Long names don't hurt, so don't get lazy! Prefixes and suffixes can go a long way to clarifying the symbols use.
cdr_large_knob_manip -- A custom dataref that is driven (written to) by a manipulator
cdr_large_knob_anim -- A custom dataref that drives an OBJ animation
cdr_pilot_alt_tens_digit_wheel_ratio_anim -- A custom dataref that drives an animated altimeter scrollwheel
ccb_avitab_stow_handler -- A Custom command CallBack that manages(handles) a tablet animation
ccmd_toggle_sunvisor_position -- A Custom command handle to toggle a sunvisor position animation
Do Nothing Write Callbacks
Many required callbacks, for both commands and datarefs have no need to do anything. When this is the case, then use one single callback named "do_nothing_CB" and pass this callback name as a parameter whenever your callbacks do not need to do anything. This will save you the time of writing multiple callbacks for other commands and datarefs that all do nothing, as well as let you know in the declaration statement itself that the command/write dataref callbacks do nothing. =
Button Presses
Whenever you need to process a simple click in 3D, i.e. "push/press" a button or click on a handle, then prefer to use a COMMAND type manipulator and the XLua command callbacks, rather than the older button type manipulator, which uses a Dataref write Callback. You can animate such buttons by assigning them the "virtual dataref": CMND=your/command/string/name in Blender, or alternatively, you can create a dedicated animation dataref if you so desire.