Lua Scripting - MOARdV/AvionicsSystems GitHub Wiki

Lua scripting provides a great deal of extensibility to MAS. Using a Lua script in a collider action or variable makes it possible to do far more than RPM or even basic MAS allows.

Lua scripts themselves should be placed in text files, with an extension of ".lua" by convention. The Lua functionality is provided via the MoonSharp C# Lua interpreter. For MAS, MoonSharp is configured in "Hard Sandbox" mode with the "LoadMethods" extension, meaning that the only Lua standard libraries that are enabled are the Strings library, the Math library, global constants, and tables and table iterators. In addition, the "LoadMethods" capability allows functions to be compiled in Lua from text, permitting runtime creation of new functions.

To allow MAS to load these Lua scripts into the MAS script environment, a config node must be included somewhere in a config file that tells MAS about these Lua scripts, such as (from MOARdV/Scripts/MAS_Scripts.cfg):

MAS_LUA
{
	name = MAS_Scripts

	script = MOARdV/Scripts/MAS_Clock.lua
	script = MOARdV/Scripts/MAS_MJComp.lua
}

The name field simply provides a name for the node. The name is used when reporting errors to make it easier to track down the problem script.

Each Lua script should be listed on a separate script line, as shown above.

Within each Lua script file, one or more functions and local variables may be listed. For instance, the MAS_Clock.lua script listed above includes four Lua functions, such as

-- Return either UT (mode 1) or MET (mode 2).  Or 0 if the unit is off.
function MAS_Clock_Time()
	if fc.GetPersistentAsNumber("MAS_Clock_On") < 1 then
		return 0
	elseif fc.GetPersistentAsNumber("MAS_Clock_ClockMode") > 0 then
		-- MET
		local met = fc.MET()
		-- Clamp MET to display limits
		met = math.min(met, 3599999)
		return met
	else
		-- Only keep HH/MM/SS of UT
		return fc.TimeOfDay(fc.UT())
	end
end

There are no MAS-imposed restrictions on how many functions go in a single script, but it's a good rule-of-thumb to organize each script file around a common theme. For instance, MAS_Clock.lua has the functions relevant to the Clock / Time panel.

Dynamic Functions

When using the load() feature to create functions on the fly, be aware that such functions can not be called directly from variables or other locations outside of the script in which they were created. If you wish to access those functions externally, you must use a wrapper function, such as:

function myDynamicFunction()
  return 0
end

function DynamicFunctionWrapper()
  return myDynamicFunction()
end

function MakeNewDynamicFunction()
  local newFn, error = load(...)
  if newFn ~= nil then
    myDynamicFunction = newFn
  end
end

In the above example, if a variable in a config file is set to myDynamicFunction(), it will always return 0, even if MakeNewDynamicFunction() replaces it. However, DynamicFunctionWrapper() will reflect the updated version of the function after MakeNewDynamicFunction() changes it.

Lua Tips

First, a warning: Lua is slow. It is an interpreted language, and functions running in Lua take close to 10x as long to evaluate as a simple C# expression. Since the whole point of Lua is to provide customized functionality, Lua functions are often complex, as well, which can make the evaluation even slower. To confound matters, the MoonSharp DLL has a tendency to generate a lot of temporary allocations, leading to more frequent garbage collection. For these reasons, Lua scripts should be used very sparingly in variable and text blocks.

On the other hand, Lua is well-suited for triggered events (either as part of a COLLIDER_EVENT or a TRIGGER_EVENT that doesn't auto-repeat), where the complex behavior of a Lua script can enhance the immersive experience.