-
Notifications
You must be signed in to change notification settings - Fork 27
Lua Scripting
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.
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.
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.