Data hosted with ♥ by Pastebin.com - Download Raw - See Original
  1. name: Basic Space Autopilot
  2. slots:
  3.   core:
  4.     class: CoreUnit
  5.   container:
  6.     class: FuelContainer
  7.     select: all
  8. handlers:
  9.   unit:
  10.     start:
  11.       lua: |
  12.        -- Garbage collection fix added by wrap.lua
  13.         do
  14.           -- Set GC pause. This more or less means by how many % memory use should increase before a garbage collection is started. Lua default is 200
  15.           local newPause = 110
  16.           local oldPause = collectgarbage("setpause", newPause)
  17.        
  18.           if oldPause < newPause then
  19.             -- DU now has a different default GC pause which is even lower. Revert back to it.
  20.             collectgarbage("setpause", oldPause)
  21.           end
  22.         end
  23.         -- error handling code added by wrap.lua
  24.         __wrap_lua__stopped = false
  25.         __wrap_lua__stopOnError = false
  26.         __wrap_lua__rethrowErrorAlways = false
  27.         __wrap_lua__rethrowErrorIfStopped = true
  28.         __wrap_lua__printError = true
  29.         __wrap_lua__showErrorOnScreens = true
  30.        
  31.         function __wrap_lua__error (message)
  32.           if __wrap_lua__stopped then return end
  33.        
  34.           -- make the traceback more readable and escape HTML syntax characters
  35.           message = tostring(message):gsub('"%-%- |STDERROR%-EVENTHANDLER[^"]*"', 'chunk'):gsub("&", "&amp;"):gsub("<", "&lt;"):gsub(">", "&gt;")
  36.        
  37.           local unit = unit or self or {}
  38.        
  39.           if __wrap_lua__showErrorOnScreens then
  40.             for _, value in pairs(unit) do
  41.               if type(value) == "table" and value.setCenteredText and value.setHTML then -- value is a screen
  42.                 if message:match("\n") then
  43.                   value.setHTML([[
  44.         <pre style="color: white; background-color: black; font-family: Consolas,monospace; font-size: 4vh; white-space: pre-wrap; margin: 1em">
  45.         Error: ]] .. message .. [[
  46.         </pre>]])
  47.                 else
  48.                   value.setCenteredText(message)
  49.                 end
  50.               end
  51.             end
  52.           end
  53.        
  54.           if __wrap_lua__printError and system and system.print then
  55.             system.print("Error: " .. message:gsub("\n", "<br>"))
  56.           end
  57.        
  58.           if __wrap_lua__stopOnError then
  59.             __wrap_lua__stopped = true
  60.           end
  61.        
  62.           if __wrap_lua__stopped and unit and unit.exit then
  63.             unit.exit()
  64.           end
  65.        
  66.           if __wrap_lua__rethrowErrorAlways or (__wrap_lua__stopped and __wrap_lua__rethrowErrorIfStopped) then
  67.             error(message)
  68.           end
  69.         end
  70.        
  71.         -- in case traceback is removed or renamed
  72.         __wrap_lua__traceback = traceback or (debug and debug.traceback) or function (arg1, arg2) return arg2 or arg1 end
  73.        
  74.         local ok, message = xpcall(function ()
  75.        
  76.         -- script code
  77.        
  78.         --------------------------------------------------------------------------------
  79.         -- basic space autopilot bundle begins
  80.         -- version: 2020-05-13 82cd7bd
  81.         -- content sha256: 73a16d5558
  82.         --------------------------------------------------------------------------------
  83.         __lbs__version = "2020-05-13 82cd7bd"
  84.         do
  85.        
  86.         do
  87.         local _ENV = _ENV
  88.         package.preload[ "common.Switcher" ] = function( ... ) _ENV = _ENV;
  89.         ---@generic TItem
  90.         ---@param items TItem[]
  91.         ---@param onSwitched nil | fun(item:TItem,index:number)
  92.         local function createSwitcher (items, onSwitched)
  93.           local self = {} ---@class Switcher
  94.        
  95.           local index = 1
  96.        
  97.           function self.switchToNext ()
  98.             if index == #items then
  99.               self.switchToIndex(1)
  100.             else
  101.               self.switchToIndex(index + 1)
  102.             end
  103.           end
  104.        
  105.           function self.switchToPrevious ()
  106.             if index == 1 then
  107.               self.switchToIndex(#items)
  108.             else
  109.               self.switchToIndex(index - 1)
  110.             end
  111.           end
  112.        
  113.           ---@param newIndex number
  114.           function self.switchToIndex (newIndex)
  115.             local previousIndex = index
  116.             index = newIndex
  117.        
  118.             if onSwitched then
  119.               onSwitched(items[index], items[previousIndex])
  120.             end
  121.           end
  122.        
  123.           ---@param item TItem
  124.           function self.switchToItem (item)
  125.             for itemIndex = 1, #items do
  126.               if items[itemIndex] == item then
  127.                 return self.switchToIndex(itemIndex)
  128.               end
  129.             end
  130.        
  131.             error("item was not found and cannot be switched to")
  132.           end
  133.        
  134.           function self.getIndex ()
  135.             return index
  136.           end
  137.        
  138.           function self.getCurrent ()
  139.             return items[index]
  140.           end
  141.        
  142.           return self
  143.         end
  144.        
  145.         return { new = createSwitcher }
  146.        
  147.         end
  148.         end
  149.        
  150.         do
  151.         local _ENV = _ENV
  152.         package.preload[ "common.utils.array.add" ] = function( ... ) _ENV = _ENV;
  153.         --- Creates a new array that has items from all argument arrays added in sequence.
  154.         --- concat would be a better name, but there already is table.concat that does something else.
  155.         ---@generic TItem
  156.         ---@vararg TItem[]
  157.         ---@return TItem[]
  158.         local function add (...)
  159.           local result = {}
  160.           local arrays = { ... }
  161.        
  162.           for arrayIndex = 1, #arrays do
  163.             local array = arrays[arrayIndex]
  164.        
  165.             for elementIndex = 1, #array do
  166.               result[#result + 1] = array[elementIndex]
  167.             end
  168.           end
  169.        
  170.           return result
  171.         end
  172.        
  173.         return add
  174.        
  175.         end
  176.         end
  177.        
  178.         do
  179.         local _ENV = _ENV
  180.         package.preload[ "common.utils.array.filter" ] = function( ... ) _ENV = _ENV;
  181.         ---@generic TItem
  182.         ---@param arr TItem[]
  183.         ---@param predicate fun(item:TItem,index:number):boolean
  184.         local function filter (arr, predicate)
  185.           local result = {} ---@type TItem[]
  186.        
  187.           for index = 1, #arr do
  188.             local item = arr[index]
  189.             if predicate(item, index) then
  190.               result[#result + 1] = item
  191.             end
  192.           end
  193.        
  194.           return result
  195.         end
  196.        
  197.         return filter
  198.        
  199.         end
  200.         end
  201.        
  202.         do
  203.         local _ENV = _ENV
  204.         package.preload[ "common.utils.array.findOneMatching" ] = function( ... ) _ENV = _ENV;
  205.         --- Returns the first item matching the predicate.
  206.         ---@generic TItem
  207.         ---@param items TItem[]
  208.         ---@param predicate fun(item:TItem):boolean
  209.         ---@return TItem|nil, number|nil
  210.         local function findOneMatching (items, predicate)
  211.           for index, item in ipairs(items) do
  212.             if predicate(item) then
  213.               return item, index
  214.             end
  215.           end
  216.         end
  217.        
  218.         return findOneMatching
  219.        
  220.         end
  221.         end
  222.        
  223.         do
  224.         local _ENV = _ENV
  225.         package.preload[ "common.utils.array.map" ] = function( ... ) _ENV = _ENV;
  226.         -- https://en.wikibooks.org/wiki/Lua_Functional_Programming/Functions
  227.        
  228.         ---@generic TSource, TResult
  229.         ---@param array TSource[]
  230.         ---@param func fun(item:TSource,index:number):TResult
  231.         ---@return TResult[]
  232.         local function map (array, func)
  233.           local new_array = {}
  234.        
  235.           for index, value in ipairs(array) do
  236.             new_array[index] = func(value,index)
  237.           end
  238.        
  239.           return new_array
  240.         end
  241.        
  242.         return map
  243.        
  244.         end
  245.         end
  246.        
  247.         do
  248.         local _ENV = _ENV
  249.         package.preload[ "common.utils.array.orderedInsert" ] = function( ... ) _ENV = _ENV;
  250.         local format = string.format
  251.         local insert = table.insert
  252.        
  253.         --- Insert one value into an already ordered array to a position determined by a weights dictionary.
  254.         --- This might be a bit more efficient than (re-)sorting a short array with a custom compare function.
  255.         --- For efficiency with larger arrays this function could use binary search (not implemented).
  256.         ---@generic TItem, TWeight
  257.         ---@param arr TItem[]
  258.         ---@param weights table<TItem, TWeight>
  259.         ---@param val TItem
  260.         ---@return number Inserted value's index in the array.
  261.         local function orderedInsert (arr, weights, val)
  262.           if #arr == 0 then
  263.             arr[1] = val
  264.             return 1
  265.           end
  266.        
  267.           local valWeight = weights[val]
  268.           if not valWeight then
  269.             error(format("value to be inserted (%s) is not in the weights table", val))
  270.           end
  271.        
  272.           for i = 1, #arr do
  273.             local nextVal = arr[i]
  274.             local nextWeight = weights[nextVal]
  275.        
  276.             if not nextWeight then
  277.               error(format("value at index %d (%s) is not in the weights table", i, nextVal))
  278.             end
  279.        
  280.             if nextWeight > valWeight then
  281.               insert(arr, i, val)
  282.               return i
  283.             end
  284.           end
  285.        
  286.           arr[#arr + 1] = val
  287.           return #arr
  288.         end
  289.        
  290.         return orderedInsert
  291.        
  292.         end
  293.         end
  294.        
  295.         do
  296.         local _ENV = _ENV
  297.         package.preload[ "common.utils.formatDecimal" ] = function( ... ) _ENV = _ENV;
  298.         local format, match = string.format, string.match
  299.        
  300.         -- like string format "%.5f", except that trailing zeroes are removed
  301.         ---@param number number
  302.         ---@param maxDecimalDigits number
  303.         ---@return string
  304.         local function formatDecimal (number, maxDecimalDigits)
  305.           local formatString = format("%%.%df", maxDecimalDigits)
  306.           local numberString = format(formatString, number)
  307.        
  308.           if maxDecimalDigits < 2 then
  309.             return numberString
  310.           end
  311.        
  312.           return match(numberString, "^([^.]*...-)0*$")
  313.         end
  314.        
  315.         return formatDecimal
  316.        
  317.         end
  318.         end
  319.        
  320.         do
  321.         local _ENV = _ENV
  322.         package.preload[ "common.utils.formatTimeWithUnits" ] = function( ... ) _ENV = _ENV;
  323.         local floor = math.floor
  324.         local concat = table.concat
  325.        
  326.         local secondsInMinute = 60
  327.         local secondsInHour = secondsInMinute * 60
  328.         local secondsInDay = secondsInHour * 24
  329.         local secondsInYear = 365.2419 * secondsInDay
  330.        
  331.         local minTotalSecondsToShowOnlyYears = secondsInYear * 10
  332.        
  333.         ---@param totalSeconds number
  334.         ---@param maxComponents nil|number
  335.         local function formatTimeWithUnits (totalSeconds, maxComponents)
  336.           maxComponents = maxComponents or 2
  337.        
  338.           local buffer = {}
  339.        
  340.           if totalSeconds < 0 then
  341.             buffer[#buffer + 1] = "-"
  342.             totalSeconds = -totalSeconds
  343.             maxComponents = maxComponents + 1
  344.           end
  345.        
  346.           local showOnlyYears = totalSeconds > minTotalSecondsToShowOnlyYears
  347.        
  348.           local years = floor(totalSeconds / secondsInYear)
  349.           if years > 0 then buffer[#buffer + 1] = years .. "y" end
  350.        
  351.           if #buffer < maxComponents and not showOnlyYears then
  352.             local days = floor(totalSeconds % secondsInYear / secondsInDay)
  353.             if days > 0 then buffer[#buffer + 1] = days .. "d" end
  354.           end
  355.        
  356.           if #buffer < maxComponents and not showOnlyYears then
  357.             local hours = floor(totalSeconds % secondsInDay / secondsInHour)
  358.             if hours > 0 then buffer[#buffer + 1] = hours .. "h" end
  359.           end
  360.        
  361.           if #buffer < maxComponents and not showOnlyYears then
  362.             local minutes = floor(totalSeconds % secondsInHour / secondsInMinute)
  363.             if minutes > 0 then buffer[#buffer + 1] = minutes .. "m" end
  364.           end
  365.        
  366.           if #buffer < maxComponents and not showOnlyYears then
  367.             local seconds = floor(totalSeconds % secondsInMinute)
  368.             if seconds > 0 then buffer[#buffer + 1] = seconds .. "s" end
  369.           end
  370.        
  371.           if #buffer == 0 then return "0s" end
  372.        
  373.           return concat(buffer, " ")
  374.         end
  375.        
  376.         return formatTimeWithUnits
  377.        
  378.         end
  379.         end
  380.        
  381.         do
  382.         local _ENV = _ENV
  383.         package.preload[ "common.utils.json" ] = function( ... ) _ENV = _ENV;
  384.         -- Extracts values from a JSON string with pattern matching
  385.         -- This is faster than using dkjson when only a few fields are needed
  386.        
  387.         -- Use this only with trusted data sources! Limitations:
  388.         -- * Character escapes are not supported
  389.         -- * Field nesting is ignored
  390.        
  391.         local find, gsub = string.find, string.gsub
  392.        
  393.         ---@param json string
  394.         ---@param key string
  395.         ---@param init number|nil
  396.         ---@return string|nil, number|nil, number|nil
  397.         local function extractStringJsonValue (json, key, init)
  398.           local pattern = [["]] .. key .. [["%s*:%s*"([^"]*)"]]
  399.           local startIndex, endIndex, valueStr = find(json, pattern, init)
  400.           return valueStr, startIndex, endIndex
  401.         end
  402.        
  403.         ---@param json string
  404.         ---@param key string
  405.         ---@param init number|nil
  406.         ---@return number|nil, number|nil, number|nil
  407.         local function extractNumberJsonValue (json, key, init)
  408.           local pattern = [["]] .. key .. [["%s*:%s*(-?[0-9.e-]+)]]
  409.           local startIndex, endIndex, valueStr = find(json, pattern, init)
  410.           return tonumber(valueStr), startIndex, endIndex
  411.         end
  412.        
  413.         ---@param json string
  414.         ---@param key string
  415.         ---@param init number|nil
  416.         ---@return boolean|nil, number|nil, number|nil
  417.         local function extractBooleanJsonValue (json, key, init)
  418.           local pattern = [["]] .. key .. [["%s*:%s*([truefals]+)]]
  419.           local startIndex, endIndex, valueStr = find(json, pattern, init)
  420.        
  421.           if valueStr == "true" then
  422.             return true, startIndex, endIndex
  423.           elseif valueStr == "false" then
  424.             return false, startIndex, endIndex
  425.           else
  426.             return nil
  427.           end
  428.         end
  429.        
  430.         ---@param extractJsonValue function
  431.         ---@param json string
  432.         ---@param key string
  433.         ---@param stopAfterIndex number|nil
  434.         ---@param stopAfterValue any|nil
  435.         ---@return any[]
  436.         local function extractAllJsonValues (extractJsonValue, json, key, stopAfterIndex, stopAfterValue)
  437.           local values = {}
  438.           local valuesLen = 0
  439.        
  440.           local jsonPos = 1
  441.           local value, valueStartIndex, valueEndIndex -- luacheck: ignore valueStartIndex -- unused
  442.        
  443.           repeat
  444.             value, valueStartIndex, valueEndIndex = extractJsonValue(json, key, jsonPos)
  445.        
  446.             if value ~= nil then
  447.               valuesLen = valuesLen + 1
  448.               values[valuesLen] = value
  449.        
  450.               jsonPos = valueEndIndex + 1
  451.             end
  452.        
  453.             if value == stopAfterValue then break end
  454.             if valuesLen == stopAfterIndex then break end
  455.           until value == nil
  456.        
  457.           return values
  458.         end
  459.        
  460.         ---@param json string
  461.         ---@param key string
  462.         ---@param stopAfterIndex number|nil
  463.         ---@param stopAfterValue string|nil
  464.         ---@return string[]
  465.         local function extractAllStringJsonValues (json, key, stopAfterIndex, stopAfterValue)
  466.           return extractAllJsonValues(extractStringJsonValue, json, key, stopAfterIndex, stopAfterValue)
  467.         end
  468.        
  469.         ---@param json string
  470.         ---@param key string
  471.         ---@param stopAfterIndex number|nil
  472.         ---@param stopAfterValue number|nil
  473.         ---@return number[]
  474.         local function extractAllNumberJsonValues (json, key, stopAfterIndex, stopAfterValue)
  475.           return extractAllJsonValues(extractNumberJsonValue, json, key, stopAfterIndex, stopAfterValue)
  476.         end
  477.        
  478.         ---@param json string
  479.         ---@param key string
  480.         ---@param stopAfterIndex number|nil
  481.         ---@param stopAfterValue boolean|nil
  482.         ---@return boolean[]
  483.         local function extractAllBooleanJsonValues (json, key, stopAfterIndex, stopAfterValue)
  484.           return extractAllJsonValues(extractBooleanJsonValue, json, key, stopAfterIndex, stopAfterValue)
  485.         end
  486.        
  487.         ---@param json string
  488.         ---@param key string
  489.         ---@return string
  490.         local function deleteAllStringJsonValues (json, key)
  491.           local pattern = [[%s*"]] .. key .. [["%s*:%s*"[^"]*"%s*,?]]
  492.           return (gsub(json, pattern, ""))
  493.         end
  494.        
  495.         ---@param json string
  496.         ---@param key string
  497.         ---@return string
  498.         local function deleteAllNumberJsonValues (json, key)
  499.           local pattern = [[%s*"]] .. key .. [["%s*:%s*-?[0-9.e-]+%s*,?]]
  500.           return (gsub(json, pattern, ""))
  501.         end
  502.        
  503.         ---@param json string
  504.         ---@param key string
  505.         ---@return string
  506.         local function deleteAllBooleanJsonValue (json, key)
  507.           local pattern = [[%s*"]] .. key .. [["%s*:%s*[truefals]+%s*,?]]
  508.           return (gsub(json, pattern, ""))
  509.         end
  510.        
  511.         return {
  512.           extractStringJsonValue = extractStringJsonValue,
  513.           extractNumberJsonValue = extractNumberJsonValue,
  514.           extractBooleanJsonValue = extractBooleanJsonValue,
  515.        
  516.           extractAllStringJsonValues = extractAllStringJsonValues,
  517.           extractAllNumberJsonValues = extractAllNumberJsonValues,
  518.           extractAllBooleanJsonValues = extractAllBooleanJsonValues,
  519.        
  520.           deleteAllStringJsonValues = deleteAllStringJsonValues,
  521.           deleteAllNumberJsonValues = deleteAllNumberJsonValues,
  522.           deleteAllBooleanJsonValue = deleteAllBooleanJsonValue
  523.         }
  524.        
  525.         end
  526.         end
  527.        
  528.         do
  529.         local _ENV = _ENV
  530.         package.preload[ "common.utils.makeCounter" ] = function( ... ) _ENV = _ENV;
  531.         local maxinteger = math.maxinteger
  532.        
  533.         ---@param startValue number
  534.         return function (startValue)
  535.           startValue = startValue or 0
  536.           assert(type(startValue) == "number", "startValue must be a number")
  537.        
  538.           local value = startValue
  539.        
  540.           return function ()
  541.             local valueToReturn = value
  542.        
  543.             if value < maxinteger then
  544.               value = value + 1
  545.             else
  546.               value = 0
  547.             end
  548.        
  549.             return valueToReturn
  550.           end
  551.         end
  552.        
  553.         end
  554.         end
  555.        
  556.         do
  557.         local _ENV = _ENV
  558.         package.preload[ "common.utils.math.signedAngleBetween" ] = function( ... ) _ENV = _ENV;
  559.         local acos = math.acos
  560.        
  561.         -- angle is positive if the cross product is in the same direction as the plane normal
  562.         local function signedAngleBetween(vec1, vec2, planeNormal)
  563.           local normVec1 = vec1:normalize()
  564.           local normVec2 = vec2:normalize()
  565.        
  566.           local cosAngle = normVec1:dot(normVec2)
  567.        
  568.           -- due to floating point inaccuracy dot product can end up slightly outside acos domain
  569.           if cosAngle > 1 then
  570.             cosAngle = 1
  571.           elseif cosAngle < -1 then
  572.             cosAngle = -1
  573.           end
  574.        
  575.           local angle = acos(cosAngle)
  576.           local crossProduct = vec1:cross(vec2)
  577.        
  578.           if crossProduct:dot(planeNormal) < 0 then
  579.             return -angle
  580.           else
  581.             return angle
  582.           end
  583.         end
  584.        
  585.         return signedAngleBetween
  586.        
  587.         end
  588.         end
  589.        
  590.         do
  591.         local _ENV = _ENV
  592.         package.preload[ "common.utils.string.firstLetterToUpperCase" ] = function( ... ) _ENV = _ENV;
  593.         ---@param str string
  594.         local function firstLetterToUpperCase (str)
  595.           local result = str:gsub("^%l", function (ch)
  596.             return ch:upper()
  597.           end)
  598.        
  599.           return result
  600.         end
  601.        
  602.         return firstLetterToUpperCase
  603.        
  604.         end
  605.         end
  606.        
  607.         do
  608.         local _ENV = _ENV
  609.         package.preload[ "common.utils.string.wordsToCamelCase" ] = function( ... ) _ENV = _ENV;
  610.         ---@param str string
  611.         local function wordsToCamelCase (str)
  612.           local filteredStr = str
  613.             :lower()
  614.             :gsub("[^%a%d ]", " ")
  615.             :gsub(" +", " ")
  616.        
  617.           local result = filteredStr:gsub(" (.)", function (ch)
  618.             return ch:upper()
  619.           end)
  620.        
  621.           return result
  622.         end
  623.        
  624.         return wordsToCamelCase
  625.        
  626.         end
  627.         end
  628.        
  629.         do
  630.         local _ENV = _ENV
  631.         package.preload[ "common.utils.table.assign" ] = function( ... ) _ENV = _ENV;
  632.         -- Copies values of source tables into the target table and returns the target table
  633.         -- (like JavaScript's Object.assign)
  634.        
  635.         ---@generic TTargetTable, TCopiedTable
  636.         ---@param targetTable TTargetTable
  637.         ---@vararg TCopiedTable
  638.         ---@return TTargetTable | TCopiedTable
  639.         local function assign (targetTable, ...)
  640.           local sourceTables = { ... }
  641.        
  642.           for i = 1, #sourceTables do
  643.             for key, value in pairs(sourceTables[i]) do
  644.               targetTable[key] = value
  645.             end
  646.           end
  647.        
  648.           return targetTable
  649.         end
  650.        
  651.         return assign
  652.        
  653.         end
  654.         end
  655.        
  656.         do
  657.         local _ENV = _ENV
  658.         package.preload[ "du.CoordinateConverter" ] = function( ... ) _ENV = _ENV;
  659.         local unpack = table.unpack
  660.        
  661.         local function createCoordinateConverter (params)
  662.           params = params or {}
  663.        
  664.           local library = params.library or library
  665.        
  666.           local rightAxis = { 0, 0, 0 }
  667.           local forwardAxis = { 0, 0, 0 }
  668.           local upAxis = { 0, 0, 0 }
  669.        
  670.           local self = {} ---@class CoordinateConverter
  671.        
  672.           ---@param core Core
  673.           function self.setAxesFromCore (core)
  674.             rightAxis = core.getConstructWorldOrientationRight()
  675.             forwardAxis = core.getConstructWorldOrientationForward()
  676.             upAxis = core.getConstructWorldOrientationUp()
  677.           end
  678.        
  679.           ---@param gyro Gyro
  680.           function self.setAxesFromGyro (gyro)
  681.             rightAxis = gyro.worldRight()
  682.             forwardAxis = gyro.worldForward()
  683.             upAxis = gyro.worldUp()
  684.           end
  685.        
  686.           function self.relWorldToRightForwardUp (relWorldCoords)
  687.             if relWorldCoords.x then
  688.               relWorldCoords = { relWorldCoords:unpack() }
  689.             end
  690.        
  691.             return library.systemResolution3(rightAxis, forwardAxis, upAxis, relWorldCoords)
  692.           end
  693.        
  694.           function self.rightForwardUpToRelWorld (rightForwardUpCoords)
  695.             if rightForwardUpCoords.x then
  696.               rightForwardUpCoords = { rightForwardUpCoords:unpack() }
  697.             end
  698.        
  699.             local rightX, rightY, rightZ = unpack(rightAxis)
  700.             local forwardX, forwardY, forwardZ = unpack(forwardAxis)
  701.             local upX, upY, upZ = unpack(upAxis)
  702.        
  703.             local rfuX, rfuY, rfuZ = unpack(rightForwardUpCoords)
  704.        
  705.             -- rel = rfuX * right + rfuY * fwd + rfuZ * up
  706.        
  707.             local relX = rfuX * rightX + rfuY * forwardX + rfuZ * upX
  708.             local relY = rfuX * rightY + rfuY * forwardY + rfuZ * upY
  709.             local relZ = rfuX * rightZ + rfuY * forwardZ + rfuZ * upZ
  710.        
  711.             return { relX, relY, relZ }
  712.           end
  713.        
  714.           return self
  715.         end
  716.        
  717.         return { new = createCoordinateConverter }
  718.        
  719.         end
  720.         end
  721.        
  722.         do
  723.         local _ENV = _ENV
  724.         package.preload[ "du.Hal" ] = function( ... ) _ENV = _ENV;
  725.         -- "hardware abstraction layer" ;)
  726.         -- more exactly, a slot abstraction layer
  727.        
  728.         local filter = require "common.utils.array.filter"
  729.         local findOneMatching = require "common.utils.array.findOneMatching"
  730.         local firstLetterToUpperCase = require "common.utils.string.firstLetterToUpperCase"
  731.         local orderedInsert = require "common.utils.array.orderedInsert"
  732.         local wordsToCamelCase = require "common.utils.string.wordsToCamelCase"
  733.        
  734.         local sort = table.sort
  735.        
  736.         ---@type Control
  737.         local self = self or unit or {} -- in-game, self is the active control unit
  738.        
  739.         ---@class Hal
  740.         local Hal = {
  741.           classes = {
  742.             AtmoFuelContainer = "AtmoFuelContainer",
  743.             RocketFuelContainer = "RocketFuelContainer",
  744.             SpaceFuelContainer = "SpaceFuelContainer"
  745.           },
  746.        
  747.           slotNames = {},
  748.        
  749.           elementType = {},
  750.           elementInSlot = {},
  751.           elementSlotName = {},
  752.        
  753.           elements = {}
  754.           -- containers, databanks, etc. are added later
  755.         }
  756.        
  757.         local function isAntiGravityGenerator (element) return element.setBaseAltitude end
  758.         local function isControl (element) return element.setTimer and element.exit end
  759.         local function isContainer (element) return element.getItemsMass end
  760.         local function isCore (element) return element.spawnNumberSticker end
  761.         local function isDatabank (element) return element.getNbKeys end
  762.         local function isDynamicCore (element) return isCore(element) and element.getConstructCrossSection end
  763.         local function isElementWithState (element) return element.getState end
  764.         local function isEngine (element) return element.getMaxThrust end
  765.         local function isGyro (element) return element.worldUp end
  766.         local function isIndustry (element) return element.getCycleCountSinceStartup end
  767.         local function isLibrary (element) return element.systemResolution3 end
  768.         local function isPvpRadar (element) return element.getWidgetType and element.getWidgetType() == "radar" end
  769.         local function isRadar (element) return element.getEntries and element.getConstructWorldPos end
  770.         local function isScreen (element) return element.setCenteredText and element.setHTML end
  771.         local function isSystem (element) return element.getTime end
  772.         local function isTelemeter (element) return element.getDistance and not isEngine(element) end
  773.         local function isWeapon (element) return element.getWidgetType and element.getWidgetType() == "weapon" end
  774.         local function isMaybePressableElement (element)
  775.           return
  776.             isElementWithState(element)
  777.             and not isAntiGravityGenerator(element)
  778.             and not isEngine(element)
  779.             and not isGyro(element)
  780.             and not isScreen(element)
  781.             and not isTelemeter(element)
  782.         end
  783.        
  784.         local elementTypes = {
  785.           { predicate = isAntiGravityGenerator, singular = "anti gravity generator", plural = "anti gravity generators" },
  786.           { predicate = isControl, singular = "control", plural = "controls" },
  787.           { predicate = isContainer,  singular = "container", plural = "containers" },
  788.           { predicate = isCore, singular = "core", plural = "cores" },
  789.           { predicate = isDatabank,  singular = "databank", plural = "databanks" },
  790.           { predicate = isDynamicCore, singular = "dynamic core", plural = "dynamic cores" },
  791.           { predicate = isElementWithState, singular = "element with state", plural = "elements with state" },
  792.           { predicate = isEngine, singular = "engine", plural = "engines" },
  793.           { predicate = isGyro, singular = "gyro", plural = "gyros" },
  794.           { predicate = isIndustry, singular = "industry", plural = "industries" },
  795.           { predicate = isLibrary, singular = "library", plural = "libraries" },
  796.           { predicate = isPvpRadar, singular = "PVP radar", plural = "PVP radars" },
  797.           { predicate = isRadar, singular = "radar", plural = "radars" },
  798.           { predicate = isScreen, singular = "screen", plural = "screens" },
  799.           { predicate = isSystem, singular = "system", plural = "systems" },
  800.           { predicate = isTelemeter, singular = "telemeter", plural = "telemeters" },
  801.           { predicate = isWeapon, singular = "weapon", plural = "weapons" },
  802.           { predicate = isMaybePressableElement, singular = "maybe pressable element", plural = "maybe pressable elements" }
  803.         }
  804.        
  805.         -- set table names, getter function names and error messages for each element type
  806.        
  807.         for _, elementType in pairs(elementTypes) do
  808.           elementType.singularCamelCase = wordsToCamelCase(elementType.singular)
  809.           elementType.singularPascalCase = firstLetterToUpperCase(elementType.singularCamelCase)
  810.        
  811.           elementType.pluralCamelCase = wordsToCamelCase(elementType.plural)
  812.           elementType.pluralPascalCase = firstLetterToUpperCase(elementType.pluralCamelCase)
  813.        
  814.           elementType.typeName = elementType.singularCamelCase
  815.           elementType.tableName = elementType.pluralCamelCase
  816.        
  817.           elementType.requireOneFunctionName = "require" .. elementType.singularPascalCase
  818.           elementType.requireAtLeastOneFunctionName = "require" .. elementType.pluralPascalCase
  819.        
  820.           elementType.requireOneErrorMessage = firstLetterToUpperCase(elementType.singular) .. " is not connected."
  821.           elementType.requireAtLeastOneErrorMessage = "No " .. elementType.plural .. " are connected."
  822.         end
  823.        
  824.         -- add getter functions
  825.        
  826.         for _, elementType in pairs(elementTypes) do
  827.           Hal[elementType.requireOneFunctionName] = function ()
  828.             return Hal[elementType.tableName][1] or error(elementType.requireOneErrorMessage)
  829.           end
  830.        
  831.           Hal[elementType.requireAtLeastOneFunctionName] = function ()
  832.             local elements = Hal[elementType.tableName]
  833.             if #elements < 1 then error(elementType.requireAtLeastOneErrorMessage) end
  834.             return elements
  835.           end
  836.         end
  837.        
  838.         -- detect elements and slot names
  839.        
  840.         local unsortedElements = {}
  841.        
  842.         for key, value in pairs(self) do
  843.           if type(key) == "string" and type(value) == "table" and type(value.export) == "table" then
  844.             local slotName, element = key, value
  845.        
  846.             Hal.slotNames[#Hal.slotNames + 1] = slotName
  847.             Hal.elementInSlot[slotName] = element
  848.             Hal.elementSlotName[element] = slotName
  849.        
  850.             unsortedElements[#unsortedElements + 1] = element
  851.           end
  852.         end
  853.        
  854.         -- sort elements and slot names
  855.        
  856.         sort(Hal.slotNames)
  857.        
  858.         for _, element in ipairs(unsortedElements) do
  859.           orderedInsert(Hal.elements, Hal.elementSlotName, element)
  860.         end
  861.        
  862.         -- organize elements by type
  863.        
  864.         for _, elementType in ipairs(elementTypes) do
  865.           local elementTable = {}
  866.           local elementTypePredicate = elementType.predicate
  867.        
  868.           Hal[elementType.tableName] = elementTable
  869.        
  870.           for _, element in ipairs(Hal.elements) do
  871.             if elementTypePredicate(element) then
  872.               elementTable[#elementTable + 1] = element
  873.               Hal.elementType[element] = elementType.typeName
  874.             end
  875.           end
  876.         end
  877.        
  878.         --- used by the annotation generator
  879.         ---@private
  880.         Hal._elementTypes = elementTypes
  881.        
  882.         ---@param class string
  883.         function Hal.getElementClassPredicate (class)
  884.           ---@param element Element
  885.           return function (element)
  886.             return element.getElementClass and element.getElementClass():match(class) and true or false
  887.           end
  888.         end
  889.        
  890.         ---@param class string
  891.         ---@return Element
  892.         function Hal.getElementWithClass (class)
  893.           return findOneMatching(Hal.elements, Hal.getElementClassPredicate(class))
  894.         end
  895.        
  896.         ---@param class string
  897.         ---@return Element[]
  898.         function Hal.getElementsWithClass (class)
  899.           return filter(Hal.elements, Hal.getElementClassPredicate(class))
  900.         end
  901.        
  902.         return Hal
  903.        
  904.         end
  905.         end
  906.        
  907.         do
  908.         local _ENV = _ENV
  909.         package.preload[ "du.Timer" ] = function( ... ) _ENV = _ENV;
  910.         -- Sets a boolean to true each time the timer ticks
  911.         -- This allows, for example, handling all ticked timers in system update and calling system.setScreen only once
  912.        
  913.         local getNextTimerId = require "du.getNextTimerId"
  914.        
  915.         ---@param timerPeriod number
  916.         ---@param startDeactivated boolean
  917.         local function createTimer (timerPeriod, startDeactivated)
  918.           local self = { ticked = false } ---@class Timer
  919.        
  920.           local timerId
  921.        
  922.           function self.getIsActive ()
  923.             return timerId and true or false
  924.           end
  925.        
  926.           function self.activate ()
  927.             if not timerId then
  928.               timerId = getNextTimerId()
  929.               unit.setTimer(timerId, timerPeriod)
  930.             end
  931.           end
  932.        
  933.           function self.deactivate ()
  934.             if timerId then
  935.               unit.stopTimer(timerId)
  936.               timerId = nil
  937.             end
  938.           end
  939.        
  940.           function self.toggle ()
  941.             if self.getIsActive() then
  942.               self.deactivate()
  943.             else
  944.               self.activate()
  945.             end
  946.           end
  947.        
  948.           function self.onStart ()
  949.             if not startDeactivated then
  950.               self.activate()
  951.             end
  952.           end
  953.        
  954.           function self.onStop ()
  955.             self.deactivate()
  956.           end
  957.        
  958.           function self.onTick (tickedTimerId)
  959.             if tostring(tickedTimerId) == tostring(timerId) then
  960.               self.ticked = true
  961.             end
  962.           end
  963.        
  964.           return self
  965.         end
  966.        
  967.         return { new = createTimer }
  968.        
  969.         end
  970.         end
  971.        
  972.         do
  973.         local _ENV = _ENV
  974.         package.preload[ "du.data.planets" ] = function( ... ) _ENV = _ENV;
  975.         -- This file was generated automatically. Do not edit.
  976.         return {
  977.           {
  978.             id = 1,
  979.             name = "Madis",
  980.             type = "planet",
  981.             class = "hT",
  982.             gravity = 3.5325,
  983.             radius = 44300,
  984.             pos = {17465536, 22665536, -34464}
  985.           },
  986.           {
  987.             id = 10,
  988.             parentId = 1,
  989.             name = "Madis Moon 1",
  990.             type = "moon",
  991.             gravity = 0.785,
  992.             radius = 10000,
  993.             pos = {17448118.86, 22966848.03, 143079.98}
  994.           },
  995.           {
  996.             id = 11,
  997.             parentId = 1,
  998.             name = "Madis Moon 2",
  999.             type = "moon",
  1000.             gravity = 0.942,
  1001.             radius = 12000,
  1002.             pos = {17194626, 22243633.88, -214962.81}
  1003.           },
  1004.           {
  1005.             id = 12,
  1006.             parentId = 1,
  1007.             name = "Madis Moon 3",
  1008.             type = "moon",
  1009.             gravity = 1.1775,
  1010.             radius = 15000,
  1011.             pos = {17520617.44, 22184726.9, -309986.22}
  1012.           },
  1013.           {
  1014.             id = 2,
  1015.             name = "Alioth",
  1016.             type = "planet",
  1017.             class = "M",
  1018.             gravity = 9.891,
  1019.             radius = 126068,
  1020.             pos = {-8, -8, -126303},
  1021.             standardGravitationalParameter = 155900000000
  1022.           },
  1023.           {
  1024.             id = 21,
  1025.             parentId = 2,
  1026.             name = "Alioth Moon 1",
  1027.             type = "moon",
  1028.             gravity = 2.355,
  1029.             radius = 30000,
  1030.             pos = {-564185.78, 233791, -167448}
  1031.           },
  1032.           {
  1033.             id = 22,
  1034.             parentId = 2,
  1035.             name = "Alioth Moon 4",
  1036.             type = "moon",
  1037.             gravity = 2.380905,
  1038.             radius = 30330,
  1039.             pos = {-895203, 358389, -225602}
  1040.           },
  1041.           {
  1042.             id = 3,
  1043.             name = "Thades",
  1044.             type = "planet",
  1045.             class = "T",
  1046.             gravity = 4.867,
  1047.             radius = 49000,
  1048.             pos = {29165536, 10865536, 65536}
  1049.           },
  1050.           {
  1051.             id = 30,
  1052.             parentId = 3,
  1053.             name = "Thades Moon 1",
  1054.             type = "moon",
  1055.             gravity = 1.099,
  1056.             radius = 14000,
  1057.             pos = {29214403.49, 10907080.695, 433861.28}
  1058.           },
  1059.           {
  1060.             id = 31,
  1061.             parentId = 3,
  1062.             name = "Thades Moon 2",
  1063.             type = "moon",
  1064.             gravity = 1.1775,
  1065.             radius = 15000,
  1066.             pos = {29404194.34, 10432766.6, 19553.824}
  1067.           },
  1068.           {
  1069.             id = 4,
  1070.             name = "Talemai",
  1071.             type = "planet",
  1072.             class = "M",
  1073.             gravity = 4.553,
  1074.             radius = 57500,
  1075.             pos = {-13234464, 55765536, 465536}
  1076.           },
  1077.           {
  1078.             id = 5,
  1079.             name = "Feli",
  1080.             type = "planet",
  1081.             class = "M",
  1082.             gravity = 4.71,
  1083.             radius = 41800,
  1084.             pos = {-43534464, 22565536, -48934464}
  1085.           },
  1086.           {
  1087.             id = 50,
  1088.             parentId = 5,
  1089.             name = "Feli Moon 1",
  1090.             type = "moon",
  1091.             gravity = 1.099,
  1092.             radius = 14000,
  1093.             pos = {-43902841.78, 22261034.7, -48862386}
  1094.           },
  1095.           {
  1096.             id = 6,
  1097.             name = "Sicari",
  1098.             type = "planet",
  1099.             class = "M",
  1100.             gravity = 4.0035,
  1101.             radius = 51100,
  1102.             pos = {52765536, 27165536, 52065536}
  1103.           },
  1104.           {
  1105.             id = 7,
  1106.             name = "Sinnen",
  1107.             type = "planet",
  1108.             class = "hT",
  1109.             gravity = 4.3175,
  1110.             radius = 54950,
  1111.             pos = {58665536, 29665536, 58165536}
  1112.           },
  1113.           {
  1114.             id = 70,
  1115.             parentId = 7,
  1116.             name = "Sinnen Moon 1",
  1117.             type = "moon",
  1118.             gravity = 1.3344999551773071,
  1119.             radius = 17000,
  1120.             pos = {58969618.12, 29797943.44, 57969448.98}
  1121.           },
  1122.           {
  1123.             id = 8,
  1124.             name = "Teoma",
  1125.             type = "planet",
  1126.             class = "M",
  1127.             gravity = 4.7885,
  1128.             radius = 62000,
  1129.             pos = {80865536, 54665536, -934464}
  1130.           },
  1131.           {
  1132.             id = 9,
  1133.             name = "Jago",
  1134.             type = "planet",
  1135.             class = "M",
  1136.             gravity = 4.9455,
  1137.             radius = 61590,
  1138.             pos = {-94134464, 12765536, -3634464}
  1139.           },
  1140.           {
  1141.             id = 100,
  1142.             name = "Lacobus",
  1143.             type = "planet",
  1144.             class = "hP",
  1145.             gravity = 4.4745,
  1146.             radius = 55650,
  1147.             pos = {98865536, -13534464, -934464}
  1148.           },
  1149.           {
  1150.             id = 101,
  1151.             parentId = 100,
  1152.             name = "Lacobus Moon 3",
  1153.             type = "moon",
  1154.             gravity = 1.1775,
  1155.             radius = 15000,
  1156.             pos = {98905290.17, -13950923.06, -647589.28}
  1157.           },
  1158.           {
  1159.             id = 102,
  1160.             parentId = 100,
  1161.             name = "Lacobus Moon 1",
  1162.             type = "moon",
  1163.             gravity = 1.413,
  1164.             radius = 18000,
  1165.             pos = {99180967.44, -13783860.94, -926156.934}
  1166.           },
  1167.           {
  1168.             id = 103,
  1169.             parentId = 100,
  1170.             name = "Lacobus Moon 2",
  1171.             type = "moon",
  1172.             gravity = 1.099,
  1173.             radius = 14000,
  1174.             pos = {99250054.22, -13629215.266, -1059341.74}
  1175.           },
  1176.           {
  1177.             id = 110,
  1178.             name = "Symeon",
  1179.             type = "planet",
  1180.             class = "hP",
  1181.             gravity = 3.8465,
  1182.             radius = 49050,
  1183.             pos = {14165536, -85634464, -934464}
  1184.           },
  1185.           {
  1186.             id = 120,
  1187.             name = "Ion",
  1188.             type = "planet",
  1189.             class = "hP",
  1190.             gravity = 3.5325,
  1191.             radius = 44950,
  1192.             pos = {2865536, -99034464, -934464}
  1193.           },
  1194.           {
  1195.             id = 121,
  1196.             parentId = 120,
  1197.             name = "Ion Moon 1",
  1198.             type = "moon",
  1199.             gravity = 0.8635,
  1200.             radius = 11000,
  1201.             pos = {2472917.9, -99133746.266, -1133581.06}
  1202.           },
  1203.           {
  1204.             id = 122,
  1205.             parentId = 120,
  1206.             name = "Ion Moon 2",
  1207.             type = "moon",
  1208.             gravity = 1.1775,
  1209.             radius = 15000,
  1210.             pos = {2995424.17, -99275008.73, -1378482.03}
  1211.           }
  1212.         }
  1213.         end
  1214.         end
  1215.        
  1216.         do
  1217.         local _ENV = _ENV
  1218.         package.preload[ "du.formatDistance" ] = function( ... ) _ENV = _ENV;
  1219.         local formatDecimal = require "common.utils.formatDecimal"
  1220.        
  1221.         local M_IN_KM = 1000
  1222.         local M_IN_SU = 200000
  1223.        
  1224.         ---@param distanceInMeters number
  1225.         ---@param kmDisplayThreshold nil|number
  1226.         ---@param suDisplayThreshold nil|number
  1227.         local function formatDistance (distanceInMeters, kmDisplayThreshold, suDisplayThreshold)
  1228.           kmDisplayThreshold = kmDisplayThreshold or M_IN_KM
  1229.           suDisplayThreshold = suDisplayThreshold or M_IN_SU
  1230.        
  1231.           if distanceInMeters > suDisplayThreshold or distanceInMeters < -suDisplayThreshold then
  1232.             local distanceInSu = distanceInMeters / M_IN_SU
  1233.             return formatDecimal(distanceInSu, 2) .. " su"
  1234.           elseif distanceInMeters > kmDisplayThreshold or distanceInMeters < -kmDisplayThreshold then
  1235.             local distanceInKm = distanceInMeters / M_IN_KM
  1236.             return formatDecimal(distanceInKm, 2) .. " km"
  1237.           else
  1238.             return formatDecimal(distanceInMeters, 2) .. " m"
  1239.           end
  1240.         end
  1241.        
  1242.         return formatDistance
  1243.        
  1244.         end
  1245.         end
  1246.        
  1247.         do
  1248.         local _ENV = _ENV
  1249.         package.preload[ "du.getKnownPlanets" ] = function( ... ) _ENV = _ENV;
  1250.         local assign = require "common.utils.table.assign"
  1251.         local filter = require "common.utils.array.filter"
  1252.         local map = require "common.utils.array.map"
  1253.         local planetsData = require "du.data.planets"
  1254.        
  1255.         ---@class Planet
  1256.         ---@field id number
  1257.         ---@field parentId nil|number
  1258.         ---@field name string
  1259.         ---@field type string
  1260.         ---@field class nil|string
  1261.         ---@field gravity number
  1262.         ---@field radius number
  1263.         ---@field pos table vec3
  1264.         ---@field coreAltitudeOffset nil|number the difference between the altitude reported by the core and the "real" altitude
  1265.         ---@field standardGravitationalParameter nil|number a better estimate of the standard gravitational parameter
  1266.        
  1267.         local function isPlanetDataPresent (planetData)
  1268.           return
  1269.             planetData and
  1270.             planetData.gravity and
  1271.             planetData.name and
  1272.             planetData.radius and
  1273.             planetData.pos
  1274.         end
  1275.        
  1276.         ---@return Planet[]
  1277.         local function getKnownPlanets ()
  1278.           local planetsWithoutMissingAttributes = filter(planetsData, isPlanetDataPresent)
  1279.        
  1280.           return map(planetsWithoutMissingAttributes, function (planet)
  1281.             return assign({}, planet, {
  1282.               pos = vec3(planet.pos)
  1283.             })
  1284.           end)
  1285.         end
  1286.        
  1287.         return getKnownPlanets
  1288.        
  1289.         end
  1290.         end
  1291.        
  1292.         do
  1293.         local _ENV = _ENV
  1294.         package.preload[ "du.getNextTimerId" ] = function( ... ) _ENV = _ENV;
  1295.         -- In v0.8, timer ids were shared by locally running scripts and max timer id was 2147483647 (2^31-1).
  1296.         -- Since v0.10, timer ids are local to control units and are strings.
  1297.         -- Integer ids still work and can be used with * filters, but need to be compared like tostring(setTimerId) == tostring(tickedTimerId).
  1298.        
  1299.         if _timerIdCounter then
  1300.           return _timerIdCounter
  1301.         end
  1302.        
  1303.         local makeCounter = require "common.utils.makeCounter"
  1304.        
  1305.         local firstTimerId = (__sessionId or math.random(0, 999999999)) % 2000000000 // 10000 * 10000
  1306.         _timerIdCounter = makeCounter(firstTimerId)
  1307.        
  1308.         return function ()
  1309.           return tostring(_timerIdCounter())
  1310.         end
  1311.        
  1312.         end
  1313.         end
  1314.        
  1315.         do
  1316.         local _ENV = _ENV
  1317.         package.preload[ "du.math.estimateBrakingDistance" ] = function( ... ) _ENV = _ENV;
  1318.         local cos, sin, sqrt = math.cos, math.sin, math.sqrt
  1319.        
  1320.         local c = 30000 / 3.6 -- m/s
  1321.        
  1322.         ---@param force number
  1323.         ---@param restMass number
  1324.         ---@param currentSpeed number
  1325.         ---@param brakeTime number
  1326.         ---@return number
  1327.         local function estimateBrakingDistance (force, restMass, currentSpeed, brakeTime)
  1328.           local F, m0, v0, u = force, restMass, currentSpeed, brakeTime
  1329.        
  1330.           -- integrate [ c sin((F t)/(c m0) + sin^(-1)(v0/c)) dt ] t=0..u
  1331.           -- d = (c (c m0 sqrt(1 - v0^2/c^2) - c m0 sqrt(1 - v0^2/c^2) cos((F u)/(c m0)) + m0 v0 sin((F u)/(c m0))))/F
  1332.           -- a = c m0 sqrt(1 - v0^2/c^2); b = (F u)/(c m0); d = (c (a - a cos(b) + m0 v0 sin(b)))/F
  1333.        
  1334.           local a = c * m0 * sqrt(1 - v0 * v0 / c / c)
  1335.           local b = (F * u) / (c * m0)
  1336.           return (c * (a - a * cos(b) + m0 * v0 * sin(b))) / F
  1337.         end
  1338.        
  1339.         return estimateBrakingDistance
  1340.        
  1341.         end
  1342.         end
  1343.        
  1344.         do
  1345.         local _ENV = _ENV
  1346.         package.preload[ "du.math.estimateBrakingTime" ] = function( ... ) _ENV = _ENV;
  1347.         local asin = math.asin
  1348.        
  1349.         local c = 30000 / 3.6 -- m/s
  1350.        
  1351.         ---@param force number
  1352.         ---@param restMass number
  1353.         ---@param currentSpeed number
  1354.         ---@param targetSpeed number
  1355.         ---@return number
  1356.         local function estimateBrakingTime (force, restMass, currentSpeed, targetSpeed)
  1357.           local F, m0, v0, v_target = force, restMass, currentSpeed, targetSpeed
  1358.        
  1359.           -- v'(t)=F / (m0 / sqrt(1 - ( (v(t))/c)**2) ), v(0)=v0
  1360.           -- v(t)=c sin((F t)/(c m0) + sin^(-1)(v0/c))
  1361.        
  1362.           -- solve [ c sin((F t)/(c m0) + sin^(-1)(v0/c)) = k ] for t
  1363.           -- t = (c m0 sin^(-1)(k/c) - c m0 sin^(-1)(v0/c))/F
  1364.        
  1365.           return (c * m0 * asin(v_target / c) - c * m0 * asin(v0 / c) ) / F
  1366.         end
  1367.        
  1368.         return estimateBrakingTime
  1369.        
  1370.         end
  1371.         end
  1372.        
  1373.         do
  1374.         local _ENV = _ENV
  1375.         package.preload[ "pilot.components.CompositeComponent" ] = function( ... ) _ENV = _ENV;
  1376.         ---@param components table[]
  1377.         local function createCompositeComponent (components)
  1378.           assert(type(components) == "table", "components must be table")
  1379.        
  1380.           local self = {} ---@class CompositeComponent
  1381.           setmetatable(self, self)
  1382.        
  1383.           self.__index = function (tbl, key)
  1384.             local function callEventHandlers (...)
  1385.               for i = 1, #components do
  1386.                 local eventHandler = components[i][key]
  1387.                 if eventHandler then eventHandler(...) end
  1388.               end
  1389.             end
  1390.        
  1391.             tbl[key] = callEventHandlers
  1392.             return callEventHandlers
  1393.           end
  1394.        
  1395.           return self
  1396.         end
  1397.        
  1398.         return { new = createCompositeComponent }
  1399.        
  1400.         end
  1401.         end
  1402.        
  1403.         do
  1404.         local _ENV = _ENV
  1405.         package.preload[ "pilot.components.DefaultWidgetComponent" ] = function( ... ) _ENV = _ENV;
  1406.         ---@class DefaultWidgetGroup
  1407.         ---@field panelLabel string
  1408.         ---@field widgetType string
  1409.         ---@field elements Element[]
  1410.         ---@field widgetPerData boolean
  1411.        
  1412.         --- Shows/hides default element widgets using the widget API.
  1413.         --- This is similar to the _autoconf.displayCategoryPanel and hideCategoryPanel helper functions that are automatically prepended after running autoconf.
  1414.         ---@param system System
  1415.         ---@param groups DefaultWidgetGroup[]
  1416.         local function createDefaultWidgetComponent (system, groups)
  1417.           local panelIds = {} ---@type string[]
  1418.        
  1419.           local self = {} --- @class DefaultWidgetComponent
  1420.        
  1421.           self.onStart = function ()
  1422.             for _, group in ipairs(groups) do
  1423.               local panelId = system.createWidgetPanel(group.panelLabel)
  1424.        
  1425.               if group.widgetPerData then
  1426.                 -- separate widget for each element
  1427.                 for _, element in ipairs(group.elements) do
  1428.                   local widgetId = system.createWidget(panelId, group.widgetType)
  1429.                   system.addDataToWidget(element.getDataId(), widgetId)
  1430.                 end
  1431.               else
  1432.                 -- same widget for all elements
  1433.                 local widgetId = system.createWidget(panelId, group.widgetType)
  1434.                 for _, element in ipairs(group.elements) do
  1435.                   system.addDataToWidget(element.getDataId(), widgetId)
  1436.                 end
  1437.               end
  1438.        
  1439.               panelIds[#panelIds + 1] = panelId
  1440.             end
  1441.           end
  1442.        
  1443.           self.onStop = function ()
  1444.             for _, panelId in ipairs(panelIds) do
  1445.               system.destroyWidgetPanel(panelId)
  1446.             end
  1447.           end
  1448.        
  1449.           return self
  1450.         end
  1451.        
  1452.         return { new = createDefaultWidgetComponent }
  1453.        
  1454.         end
  1455.         end
  1456.        
  1457.         do
  1458.         local _ENV = _ENV
  1459.         package.preload[ "pilot2.ConstructState" ] = function( ... ) _ENV = _ENV;
  1460.         -- Represents construct's state during the flush event
  1461.         -- Caches control/core/gyro function return values until reset
  1462.        
  1463.         local signedAngleBetween = require "common.utils.math.signedAngleBetween"
  1464.        
  1465.         local epsilon = constants.epsilon
  1466.        
  1467.         local function makeReturnVec3 (fn)
  1468.           if not fn then error("fn must be not be nil") end
  1469.           return function () return vec3(fn()) end
  1470.         end
  1471.        
  1472.         local ConstructState = {}
  1473.        
  1474.         function ConstructState.new (options)
  1475.           options = options or {}
  1476.        
  1477.           local self = setmetatable({ getters = {} }, ConstructState) -- lua-somewhat-minify: skip getters
  1478.        
  1479.           if options.control then self:addControlGetters(options.control) end
  1480.           if options.core then self:addCoreGetters(options.core) end
  1481.           if options.gyro then self:addGyroGetters(options.gyro) end
  1482.           if options.system then self:addSystemGetters(options.system) end
  1483.        
  1484.           return self
  1485.         end
  1486.        
  1487.         ---@param control Control
  1488.         function ConstructState:addControlGetters (control)
  1489.           local getters = self.getters
  1490.        
  1491.           getters.atmosphereDensity = control.getAtmosphereDensity
  1492.           getters.closestPlanetInfluence = control.getClosestPlanetInfluence
  1493.         end
  1494.        
  1495.         ---@param core Core
  1496.         function ConstructState:addCoreGetters (core)
  1497.           local getters = self.getters
  1498.        
  1499.           getters.constructMass = core.getConstructMass
  1500.           getters.constructIMass = core.getConstructIMass
  1501.           getters.constructId = core.getConstructId
  1502.           getters.constructWorldPos = makeReturnVec3(core.getConstructWorldPos)
  1503.           getters.constructCrossSection = makeReturnVec3(core.getConstructCrossSection)
  1504.        
  1505.           getters.altitude = core.getAltitude
  1506.           getters.g = core.g
  1507.           getters.worldGravity = makeReturnVec3(core.getWorldGravity)
  1508.           getters.worldVertical = makeReturnVec3(core.getWorldVertical)
  1509.        
  1510.           getters.angularVelocity = makeReturnVec3(core.getAngularVelocity)
  1511.           getters.worldAngularVelocity = makeReturnVec3(core.getWorldAngularVelocity)
  1512.           getters.angularAcceleration = makeReturnVec3(core.getAngularAcceleration)
  1513.           getters.worldAngularAcceleration = makeReturnVec3(core.getWorldAngularAcceleration)
  1514.           getters.velocity = makeReturnVec3(core.getVelocity)
  1515.           getters.worldVelocity = makeReturnVec3(core.getWorldVelocity)
  1516.           getters.acceleration = makeReturnVec3(core.getAcceleration)
  1517.           getters.worldAcceleration = makeReturnVec3(core.getWorldAcceleration)
  1518.        
  1519.           getters.constructOrientationUp = makeReturnVec3(core.getConstructOrientationUp)
  1520.           getters.constructOrientationRight = makeReturnVec3(core.getConstructOrientationRight)
  1521.           getters.constructOrientationForward = makeReturnVec3(core.getConstructOrientationForward)
  1522.           getters.constructWorldOrientationUp = makeReturnVec3(core.getConstructWorldOrientationUp)
  1523.           getters.constructWorldOrientationRight = makeReturnVec3(core.getConstructWorldOrientationRight)
  1524.           getters.constructWorldOrientationForward = makeReturnVec3(core.getConstructWorldOrientationForward)
  1525.        
  1526.           getters.worldAirFrictionAcceleration = makeReturnVec3(core.getWorldAirFrictionAcceleration)
  1527.           getters.worldAirFrictionAngularAcceleration = makeReturnVec3(core.getWorldAirFrictionAngularAcceleration)
  1528.        
  1529.           -- TODO: getters for max KP for each axis
  1530.           getters.maxKinematicsParameters = function () return core.getMaxKinematicsParametersAlongAxis("thrust analog longitudinal", { self.constructOrientationForward:unpack() } ) end
  1531.        
  1532.           getters.atmoFMaxPlus = function () return self.maxKinematicsParameters[1] end
  1533.           getters.atmoFMaxMinus = function () return self.maxKinematicsParameters[2] end
  1534.           getters.spaceFMaxPlus = function () return self.maxKinematicsParameters[3] end
  1535.           getters.spaceFMaxMinus = function () return self.maxKinematicsParameters[4] end
  1536.        
  1537.           getters.accelerationMagnitude = function () return self.worldAcceleration:len() end
  1538.           getters.velocityMagnitude = function () return self.worldVelocity:len() end
  1539.        
  1540.           getters.worldVelocityDirection = function () return self.worldVelocity / self.velocityMagnitude end
  1541.        
  1542.           getters.constructOrientationDown = function () return -self.constructOrientationUp end
  1543.           getters.constructOrientationLeft = function () return -self.constructOrientationLeft end
  1544.           getters.constructOrientationBackward = function () return -self.constrructOrientationForward end
  1545.           getters.constructWorldOrientationDown = function () return -self.constructWorldOrientationUp end
  1546.           getters.constructWorldOrientationLeft = function () return -self.constructWorldOrientationRight end
  1547.           getters.constructWorldOrientationBackward = function () return -self.constructWorldOrientationForward end
  1548.         end
  1549.        
  1550.         ---@param gyro Gyro
  1551.         function ConstructState:addGyroGetters (gyro)
  1552.           local getters = self.getters
  1553.        
  1554.           getters.worldUp = makeReturnVec3(gyro.worldUp)
  1555.           getters.worldForward = makeReturnVec3(gyro.worldForward)
  1556.           getters.worldRight = makeReturnVec3(gyro.worldRight)
  1557.        
  1558.           getters.worldDown = function () return -self.worldUp end
  1559.           getters.worldBackward = function () return -self.worldForward end
  1560.           getters.worldLeft = function () return -self.worldRight end
  1561.         end
  1562.        
  1563.         ---@param system System
  1564.         function ConstructState:addSystemGetters (system)
  1565.           local getters = self.getters
  1566.        
  1567.           getters.time = system.getTime
  1568.         end
  1569.        
  1570.         function ConstructState:addDerivedGetters ()
  1571.           local getters = self.getters
  1572.        
  1573.           getters.isMovingBackward = function ()
  1574.             return self.worldVelocity:dot(self.constructWorldOrientationForward) < 0
  1575.           end
  1576.           getters.isMovingTowardsGravity = function ()
  1577.             return self.worldVelocity:dot(self.worldGravity) > 0
  1578.           end
  1579.           getters.isUpsideDown = function ()
  1580.             return self.constructWorldOrientationUp:dot(self.worldVertical) > 0
  1581.           end
  1582.        
  1583.           getters.speed = function ()
  1584.             return self.velocityMagnitude * (self.isMovingBackward and -1 or 1)
  1585.           end
  1586.        
  1587.           getters.forwardVelocity = function ()
  1588.             return self.worldVelocity:project_on(self.constructWorldOrientationForward)
  1589.           end
  1590.           getters.forwardSpeed = function ()
  1591.             return self.forwardVelocity:len() * (self.isMovingBackward and -1 or 1)
  1592.           end
  1593.        
  1594.           getters.verticalVelocity = function ()
  1595.             return self.worldVelocity:project_on(self.worldGravity)
  1596.           end
  1597.           getters.verticalSpeed = function ()
  1598.             return self.verticalVelocity:len() * (self.isMovingTowardsGravity and -1 or 1)
  1599.           end
  1600.        
  1601.           getters.groundVelocity = function ()
  1602.             if self.g < epsilon then return vec3.zero end
  1603.             return self.worldVelocity:project_on_plane(self.worldVertical)
  1604.           end
  1605.           getters.groundSpeed = function ()
  1606.             if self.g < epsilon then return 0 end
  1607.             return self.groundVelocity:len() * (self.isMovingBackward and -1 or 1)
  1608.           end
  1609.        
  1610.           getters.groundRight = function ()
  1611.             if self.g < epsilon then return vec3.zero end
  1612.             return self.worldVertical:cross(self.constructWorldOrientationForward)
  1613.           end
  1614.           getters.groundForward = function ()
  1615.             if self.g < epsilon then return vec3.zero end
  1616.             return -self.worldVertical:cross(self.constructWorldOrientationRight)
  1617.           end
  1618.        
  1619.           getters.pitch = function () -- pitch up is positive
  1620.             return signedAngleBetween(self.groundForward, self.constructWorldOrientationForward, self.constructWorldOrientationRight)
  1621.           end
  1622.           getters.roll = function () -- left roll is positive
  1623.             return signedAngleBetween(self.constructWorldOrientationRight, self.groundRight, self.constructWorldOrientationForward)
  1624.           end
  1625.         end
  1626.        
  1627.         function ConstructState:__index (key)
  1628.           local getters = rawget(self, "getters") -- rawget prevents infinite recursion if getters get accidentally deleted
  1629.           local getter = getters[key]
  1630.        
  1631.           if not getter then
  1632.             return rawget(ConstructState, key)
  1633.           end
  1634.        
  1635.           local value = getter()
  1636.           self[key] = value
  1637.           return value
  1638.         end
  1639.        
  1640.         function ConstructState:reset ()
  1641.           for key, _ in pairs(self) do
  1642.             if key ~= "getters" then
  1643.               self[key] = nil
  1644.             end
  1645.           end
  1646.         end
  1647.        
  1648.         return ConstructState
  1649.        
  1650.         end
  1651.         end
  1652.        
  1653.         do
  1654.         local _ENV = _ENV
  1655.         package.preload[ "scripts.flight-space-autopilot.BasicAutopilotFlightMode" ] = function( ... ) _ENV = _ENV;
  1656.         local json = require "common.utils.json"
  1657.         local CoordinateConverter = require "du.CoordinateConverter"
  1658.         local ConstructState = require "pilot2.ConstructState"
  1659.        
  1660.         local deg2rad, epsilon = constants.deg2rad, constants.epsilon
  1661.         local extractNumberJsonValue = json.extractNumberJsonValue
  1662.         local rangeMap = utils.map
  1663.        
  1664.         local KM_H_TO_M_S = 1 / 3.6
  1665.        
  1666.         -- auto-alignment settings
  1667.         local minAlignmentVectorLen = 0.001
  1668.         local radiansToSlowdownAfter = 90 * deg2rad
  1669.         local rotationSpeed = 0.5
  1670.        
  1671.         -- settings for converting angular velocity to angular acceleration
  1672.         local torqueFactor = 10 --export: Force factor applied to reach the target angular velocity.
  1673.         local maxAngularAcceleration = 1 --export: Decrease this value to prevent "torque overload" messages.
  1674.        
  1675.         -- speed correction with engines
  1676.         local minSpeedErrorToCorrect = 0.4 * KM_H_TO_M_S
  1677.         local minSpeedErrorForMaxAcceleration = 7 * KM_H_TO_M_S
  1678.        
  1679.         -- brake settings
  1680.         local brakeSpeedFactor = 10 --export: When braking, brake acceleration will be equal to velocity multiplied by this number.
  1681.         local minSpeedErrorForBraking = 0.1 * KM_H_TO_M_S
  1682.        
  1683.         ---@param input number
  1684.         ---@param inputForNonZeroOutput number
  1685.         ---@param inputForMaxOutput number
  1686.         ---@param maxOutput number
  1687.         ---@return number
  1688.         local function getSpeedCorrection (input, inputForNonZeroOutput, inputForMaxOutput, maxOutput)
  1689.           if input < inputForNonZeroOutput and input > -inputForNonZeroOutput then return 0 end
  1690.        
  1691.           if input > inputForMaxOutput then return maxOutput end
  1692.           if -input > inputForMaxOutput then return -maxOutput end
  1693.        
  1694.           return rangeMap(input, inputForNonZeroOutput, inputForMaxOutput, 0, maxOutput)
  1695.         end
  1696.        
  1697.         --- Navigator.lua replacement for simple autopilot scripts.
  1698.         ---@param control Control
  1699.         ---@param core Core
  1700.         ---@param system System
  1701.         ---@param maxSpeed number|nil
  1702.         local function createAutopilotFlightMode (control, core, system, maxSpeed)
  1703.           maxSpeed = maxSpeed or 29999 * KM_H_TO_M_S
  1704.        
  1705.           local state = ConstructState.new {
  1706.             control = control,
  1707.             core = core,
  1708.             system = system
  1709.           }
  1710.           state:addDerivedGetters()
  1711.        
  1712.           local coordConverter = CoordinateConverter.new()
  1713.        
  1714.           local self = {
  1715.             state = state,
  1716.             coordConverter = coordConverter
  1717.           } ---@class BasicAutopilotFlightMode
  1718.        
  1719.           -- functions for computing angular acceleration
  1720.        
  1721.           ---@param targetAngularVelocity table vec3
  1722.           function self.composeAngularAccelerationForAngularVelocity (targetAngularVelocity)
  1723.             local currentAngularVelocity = state.worldAngularVelocity
  1724.             local airFriction = state.worldAirFrictionAngularAcceleration
  1725.        
  1726.             local angularVelocityError = targetAngularVelocity - currentAngularVelocity
  1727.             local angularAcceleration = angularVelocityError * torqueFactor - airFriction
  1728.             local angularAccelerationLength = angularAcceleration:len()
  1729.        
  1730.             if angularAccelerationLength > maxAngularAcceleration then
  1731.               angularAcceleration = angularAcceleration * (maxAngularAcceleration / angularAccelerationLength)
  1732.             end
  1733.        
  1734.             return angularAcceleration
  1735.           end
  1736.        
  1737.           ---@param currentVector table vec3
  1738.           ---@param targetVector table vec3
  1739.           ---@param angularVelocityMultiplier number|nil
  1740.           function self.composeAngularVelocityForAxisAlignment (currentVector, targetVector, angularVelocityMultiplier)
  1741.             angularVelocityMultiplier = angularVelocityMultiplier or 1
  1742.        
  1743.             local vectorsAvailable = currentVector:len() >= minAlignmentVectorLen and targetVector:len() >= minAlignmentVectorLen
  1744.             if not vectorsAvailable then return vec3.zero, nil end
  1745.        
  1746.             local rotationVector = currentVector:cross(targetVector):normalize_inplace()
  1747.        
  1748.             local radiansToAlignment = vectorsAvailable and currentVector:angle_between(targetVector) or 0
  1749.             local absRadiansToAlignment = radiansToAlignment < 0 and -radiansToAlignment or radiansToAlignment
  1750.        
  1751.             local rotationIntensity = absRadiansToAlignment / radiansToSlowdownAfter
  1752.             if rotationIntensity > 1 then rotationIntensity = 1 end
  1753.        
  1754.             local angularVelocity = rotationVector * rotationSpeed * rotationIntensity * angularVelocityMultiplier
  1755.             return angularVelocity, radiansToAlignment
  1756.           end
  1757.        
  1758.           -- functions for computing engine acceleration
  1759.        
  1760.           ---@param localAxis table vec3
  1761.           ---@param worldAxis table vec3
  1762.           ---@param isMainAxis boolean whether this is the main (usually longitudinal) axis
  1763.           ---@param currentSpeed number current speed along the axis
  1764.           ---@param targetSpeed number target speed alond the axis
  1765.           function self.composeAxisAccelerationToSpeed (localAxis, worldAxis, isMainAxis, currentSpeed, targetSpeed)
  1766.             local speedError = targetSpeed - currentSpeed
  1767.        
  1768.             local maxKP = core.getMaxKinematicsParametersAlongAxis("thrust analog space_engine", { localAxis:unpack() })
  1769.        
  1770.             local maxPlusThrust = maxKP[3]
  1771.             local maxMinusThrust = -maxKP[4]
  1772.        
  1773.             local maxThrust = speedError < 0 and maxMinusThrust or maxPlusThrust
  1774.             if maxThrust < epsilon then maxThrust = maxPlusThrust > maxMinusThrust and maxPlusThrust or maxMinusThrust end
  1775.        
  1776.             local maxAcceleration = maxThrust / state.constructMass
  1777.        
  1778.             local speedCorrection = getSpeedCorrection(speedError, minSpeedErrorToCorrect, minSpeedErrorForMaxAcceleration, maxAcceleration)
  1779.             local speedCorrectionSign = speedCorrection < 0 and -1 or 1
  1780.        
  1781.             do
  1782.               -- acceleration at near max speed works strangely. sometimes speed will not increase past 29998.4 km/h
  1783.        
  1784.               local atNearMaxSpeed =
  1785.                 state.velocityMagnitude > maxSpeed - 1 * KM_H_TO_M_S and
  1786.                 state.worldVelocityDirection:dot(worldAxis * speedCorrectionSign) > -0.1
  1787.        
  1788.               if atNearMaxSpeed then
  1789.                 if isMainAxis and state.velocityMagnitude < maxSpeed - 0.2 * KM_H_TO_M_S then
  1790.                   speedCorrection = maxAcceleration
  1791.                 else
  1792.                   speedCorrection = 0
  1793.                 end
  1794.               end
  1795.             end
  1796.        
  1797.             return speedCorrection * worldAxis
  1798.           end
  1799.        
  1800.           ---@param worldAxis table vec3
  1801.           function self.composeAxisLiftAcceleration (worldAxis)
  1802.             local gravityOnAxis = state.worldGravity:project_on(worldAxis)
  1803.             return -gravityOnAxis
  1804.           end
  1805.        
  1806.           -- functions for computing brake acceleration
  1807.        
  1808.           ---@param currentSpeed number
  1809.           ---@param targetSpeed number
  1810.           function self.composeBrakingAccelerationToSpeed (currentSpeed, targetSpeed)
  1811.             local speedError = targetSpeed - currentSpeed
  1812.        
  1813.             local shouldBrake =
  1814.               -- moving too fast forward
  1815.               targetSpeed >= 0 and currentSpeed > targetSpeed + minSpeedErrorForBraking or
  1816.               -- moving too fast backward
  1817.               targetSpeed <= 0 and currentSpeed < targetSpeed - minSpeedErrorForBraking or
  1818.               -- should be moving forward, but moving backward
  1819.               targetSpeed >= 0 and currentSpeed < -minSpeedErrorForBraking or
  1820.               -- should be moving backward, but moving forward
  1821.               targetSpeed <= 0 and currentSpeed > minSpeedErrorForBraking
  1822.        
  1823.             if not shouldBrake then return vec3.zero end
  1824.        
  1825.             local absSpeedError = speedError < 0 and -speedError or speedError
  1826.             return -state.worldVelocityDirection * absSpeedError * brakeSpeedFactor
  1827.           end
  1828.        
  1829.           function self.composeBrakingAccelerationAgainstVelocity ()
  1830.             return -state.worldVelocity * brakeSpeedFactor
  1831.           end
  1832.        
  1833.           function self.composeBrakingAccelerationAgainstGravity ()
  1834.             local brakingAcceleration = -state.worldGravity
  1835.        
  1836.             if state.verticalSpeed < 0 and state.g > epsilon then
  1837.               brakingAcceleration = brakingAcceleration + state.worldVertical * state.verticalSpeed * brakeSpeedFactor
  1838.             end
  1839.        
  1840.             return brakingAcceleration
  1841.           end
  1842.        
  1843.           function self.getMaxBrakeForce ()
  1844.             local controlData = control.getData()
  1845.             return extractNumberJsonValue(controlData, "maxBrake") or 0 -- maxBrake is missing from getData() in r0.18 until the construct moves
  1846.           end
  1847.        
  1848.           function self.getMaxVerticalSpaceForce ()
  1849.             local maxVerticalKP = core.getMaxKinematicsParametersAlongAxis("thrust analog vertical space_engine", core.getConstructOrientationUp())
  1850.             return maxVerticalKP[3]
  1851.           end
  1852.        
  1853.           ---@param tags string
  1854.           ---@param acceleration table
  1855.           ---@param angularAcceleration table
  1856.           ---@param keepForceCollinearity boolean|nil
  1857.           ---@param keepTorqueCollinearity boolean|nil
  1858.           ---@param priority1SubTags string|nil
  1859.           ---@param priority2SubTags string|nil
  1860.           ---@param priority3SubTags string|nil
  1861.           ---@param toleranceRatioToStopCommand number|nil
  1862.           function self.setEngineCommand (tags, acceleration, angularAcceleration, keepForceCollinearity, keepTorqueCollinearity, priority1SubTags, priority2SubTags, priority3SubTags, toleranceRatioToStopCommand)
  1863.             if acceleration.x then acceleration = { acceleration:unpack() } end
  1864.             if angularAcceleration.x then angularAcceleration = { angularAcceleration:unpack() }end
  1865.             if keepForceCollinearity == nil then keepForceCollinearity = true end
  1866.             if keepTorqueCollinearity == nil then keepTorqueCollinearity = true end
  1867.             if priority1SubTags == nil then priority1SubTags = "" end
  1868.             if priority2SubTags == nil then priority2SubTags = "" end
  1869.             if priority3SubTags == nil then priority3SubTags = "" end
  1870.             if toleranceRatioToStopCommand == nil then toleranceRatioToStopCommand = 0.01 end
  1871.        
  1872.             return control.setEngineCommand(tags, acceleration, angularAcceleration, keepForceCollinearity and 1 or 0, keepTorqueCollinearity and 1 or 0, priority1SubTags, priority2SubTags, priority3SubTags, toleranceRatioToStopCommand)
  1873.           end
  1874.        
  1875.           ---@param tags string
  1876.           ---@param acceleration table
  1877.           ---@param keepForceCollinearity boolean|nil
  1878.           ---@param priority1SubTags string|nil
  1879.           ---@param priority2SubTags string|nil
  1880.           ---@param priority3SubTags string|nil
  1881.           ---@param toleranceRatioToStopCommand number|nil
  1882.           function self.setEngineForceCommand (tags, acceleration, keepForceCollinearity, priority1SubTags, priority2SubTags, priority3SubTags, toleranceRatioToStopCommand)
  1883.             return self.setEngineCommand(tags, acceleration, vec3.zero, keepForceCollinearity, true, priority1SubTags, priority2SubTags, priority3SubTags, toleranceRatioToStopCommand)
  1884.           end
  1885.        
  1886.           ---@param tags string
  1887.           ---@param angularAcceleration table
  1888.           ---@param keepTorqueCollinearity boolean|nil
  1889.           ---@param priority1SubTags string|nil
  1890.           ---@param priority2SubTags string|nil
  1891.           ---@param priority3SubTags string|nil
  1892.           ---@param toleranceRatioToStopCommand number|nil
  1893.           function self.setEngineTorqueCommand (tags, angularAcceleration, keepTorqueCollinearity, priority1SubTags, priority2SubTags, priority3SubTags, toleranceRatioToStopCommand)
  1894.             return self.setEngineCommand(tags, vec3.zero, angularAcceleration, true, keepTorqueCollinearity, priority1SubTags, priority2SubTags, priority3SubTags, toleranceRatioToStopCommand)
  1895.           end
  1896.        
  1897.           function self.onBeforeFlush ()
  1898.             state:reset()
  1899.             coordConverter.setAxesFromCore(core)
  1900.           end
  1901.        
  1902.           return self
  1903.         end
  1904.        
  1905.         return { new = createAutopilotFlightMode }
  1906.        
  1907.         end
  1908.         end
  1909.        
  1910.         do
  1911.         local _ENV = _ENV
  1912.         package.preload[ "scripts.flight-space-autopilot.Script" ] = function( ... ) _ENV = _ENV;
  1913.         local add = require "common.utils.array.add"
  1914.         local estimateBrakingDistance = require "du.math.estimateBrakingDistance"
  1915.         local estimateBrakingTime = require "du.math.estimateBrakingTime"
  1916.         local formatDecimal = require "common.utils.formatDecimal"
  1917.         local formatDistance = require "du.formatDistance"
  1918.         local formatTimeWithUnits = require "common.utils.formatTimeWithUnits"
  1919.         local getKnownPlantets = require "du.getKnownPlanets"
  1920.         local BasicAutopilotFlightMode = require "scripts.flight-space-autopilot.BasicAutopilotFlightMode"
  1921.         local Switcher = require "common.Switcher"
  1922.         local Timer = require "du.Timer"
  1923.        
  1924.         local deg2rad, epsilon, rad2deg = constants.deg2rad, constants.epsilon, constants.rad2deg
  1925.        
  1926.         local clamp, rangeMap = utils.clamp, utils.map
  1927.        
  1928.         local M_S_TO_KM_H = 3.6
  1929.         local KM_H_TO_M_S = 1 / 3.6
  1930.        
  1931.         local minDistanceToDestination = 200000 -- 1 su (200 km)
  1932.        
  1933.         local targetPlanetAltitude = 80000 --export: Target altitude when autopiloting to a planet. Note that some planets (such as Feli) have a very high atmosphere.
  1934.         local targetMoonAltitude = 20000 --export: Target altitude when autopiloting to a moon.
  1935.         local targetOtherDistance = 2000 --export: Target distance when autopiloting to something that is not a moon or a planet.
  1936.        
  1937.         local minVerticalSpaceForce = 10000 -- this script requires vertical space engines for trajectory alignment
  1938.        
  1939.         local maxBrakeForceSafetyMultiplier = 0.8 -- pretend that max brake force is smaller than it is when calculating braking distance and time
  1940.         local extraSecondsToStop = 2 -- when calculating distance to start braking, subtract velocity multiplied by this number
  1941.        
  1942.         local maxSpeed = 29999 * KM_H_TO_M_S
  1943.        
  1944.         local destinations = add(
  1945.           getKnownPlantets(),
  1946.           {
  1947.             -- {
  1948.             --   name = 'Station "Aspire"',
  1949.             --   pos = vec3(39878.2726, 142748.6596, 4991603.1015)
  1950.             -- },
  1951.             -- {
  1952.             --   name = 'Station "Port Albatross"',
  1953.             --   pos = vec3(358557.0366, 1837825.7063, -175376.8116)
  1954.             -- },
  1955.             -- {
  1956.             --   name = 'Station "Myriad"',
  1957.             --   pos = vec3(-127283.7579, 138622.4415, -80552.2078)
  1958.             -- },
  1959.             -- {
  1960.             --   name = 'Station "Themis"',
  1961.             --   pos = vec3(-378454.6922, 157235.9721, -155970.3064)
  1962.             -- },
  1963.             -- {
  1964.             --   name = 'Station "ICSS"',
  1965.             --   pos = vec3(15506477.2973, 11177900.3132, -10115.5026)
  1966.             -- },
  1967.             -- {
  1968.             --   name = 'Station "Gravity Maze"',
  1969.             --   pos = vec3(-414142.7786, 217120.8101, -166107.6882)
  1970.             -- }
  1971.           }
  1972.         )
  1973.        
  1974.         ---@param control Control
  1975.         ---@param core Core
  1976.         ---@param system System
  1977.         local function createScript (control, core, system)
  1978.           local destSwitcher = Switcher.new(destinations)
  1979.        
  1980.           local selectPrevAction = "option1"
  1981.           local selectNextAction = "option2"
  1982.           local confirmSelectionAction = "option3"
  1983.        
  1984.           local screenUpdateTimer = Timer.new(1)
  1985.        
  1986.           local flight = BasicAutopilotFlightMode.new(control, core, system, maxSpeed)
  1987.           local coordConverter = flight.coordConverter
  1988.           local state = flight.state
  1989.        
  1990.           local targetDest
  1991.           local targetPos
  1992.        
  1993.           local rfuVelocity
  1994.           local driftLen
  1995.        
  1996.           local radiansToTargetVelocity
  1997.           local radiansToDrift
  1998.           local radiansToForwardAlignment
  1999.        
  2000.           local distanceToDest
  2001.           local distanceToBraking
  2002.        
  2003.           local startedBraking = false
  2004.           local arrived = false
  2005.        
  2006.           ---@param dest table
  2007.           local function getTargetDistance (dest)
  2008.             local distance = targetOtherDistance
  2009.             if dest.type == "planet" then distance = targetPlanetAltitude end
  2010.             if dest.type == "moon" then distance = targetMoonAltitude end
  2011.        
  2012.             return distance + (dest.radius or 0)
  2013.           end
  2014.        
  2015.           ---@param dest table
  2016.           local function getPosNearDestination (dest)
  2017.             local constructToDest = dest.pos - state.constructWorldPos
  2018.             local constructToDestLen = constructToDest:len()
  2019.        
  2020.             if constructToDestLen < (dest.radius or 0) + minDistanceToDestination then
  2021.               return false, "too close"
  2022.             end
  2023.        
  2024.             local destToResultDir
  2025.             if state.velocityMagnitude > 5000 * KM_H_TO_M_S then
  2026.               destToResultDir = state.worldVelocity:project_on_plane(constructToDest)
  2027.             end
  2028.             if not destToResultDir or destToResultDir:len() < epsilon then
  2029.               destToResultDir = state.constructWorldOrientationUp:cross(constructToDest)
  2030.             end
  2031.             destToResultDir:normalize_inplace()
  2032.        
  2033.             local targetDistance = getTargetDistance(dest)
  2034.             return dest.pos + destToResultDir * targetDistance
  2035.           end
  2036.        
  2037.           local function checkAutopilotForDeparture ()
  2038.             if flight.getMaxVerticalSpaceForce() < minVerticalSpaceForce then
  2039.               return false, "not enough vertical space engines"
  2040.             end
  2041.        
  2042.             if control.getAtmosphereDensity() > epsilon then
  2043.               return false, "in atmo"
  2044.             end
  2045.        
  2046.             if control.getClosestPlanetInfluence() > 0.95 then
  2047.               return false, "near surface"
  2048.             end
  2049.        
  2050.             return true
  2051.           end
  2052.        
  2053.           local function getDestinationSelectionHtml ()
  2054.             local canAutopilot, reasonCannotAutopilot = checkAutopilotForDeparture()
  2055.             if not canAutopilot then
  2056.               return "Cannot autopilot (" .. reasonCannotAutopilot .. ")"
  2057.             end
  2058.        
  2059.             local gotPos, reasonForNoPos = getPosNearDestination(destSwitcher.getCurrent())
  2060.        
  2061.             return [[
  2062.               Select destination:<br>
  2063.               <div style="font-weight: bold; padding: 0.2em 0">]] .. destSwitcher.getCurrent().name .. (gotPos and "" or " - " .. reasonForNoPos) .. [[</div>
  2064.               []] .. system.getActionKeyName(selectPrevAction) .. [[] Previous<br>
  2065.               []] .. system.getActionKeyName(selectNextAction) .. [[] Next<br>
  2066.               []] .. system.getActionKeyName(confirmSelectionAction) .. [[] Confirm<br>
  2067.             ]]
  2068.           end
  2069.        
  2070.           local function updateScreen ()
  2071.             local versionStr = __lbs__version or "Unknown version"
  2072.        
  2073.             local rfuVelocityStr = rfuVelocity and tostring(rfuVelocity) or "-"
  2074.             local speedStr = formatDecimal(state.velocityMagnitude * M_S_TO_KM_H, 2)
  2075.             local driftLenStr = driftLen and formatDecimal(driftLen * M_S_TO_KM_H, 2) or "-"
  2076.        
  2077.             local gravityStr = formatDecimal(state.g, 3)
  2078.        
  2079.             local radiansToTargetVelocityStr = radiansToTargetVelocity and formatDecimal(radiansToTargetVelocity * rad2deg, 2) or "-"
  2080.             local radiansToForwardAlignmentStr = radiansToForwardAlignment and formatDecimal(radiansToForwardAlignment * rad2deg, 2) or "-"
  2081.             local radiansToDriftStr = radiansToDrift and formatDecimal(radiansToDrift * rad2deg, 2) or "-"
  2082.        
  2083.             local selectedDestStr = targetDest and targetDest.name or "-"
  2084.             local distanceToDestStr = distanceToDest and formatDistance(distanceToDest) or "-"
  2085.             local distanceToBrakingStr = distanceToBraking and formatDistance(distanceToBraking) or "-"
  2086.        
  2087.             local timeToBrakingStr
  2088.             if distanceToBraking and not startedBraking and state.speed > maxSpeed * 0.9 then
  2089.               local timeToBraking = distanceToBraking / state.speed
  2090.               timeToBrakingStr = formatTimeWithUnits(timeToBraking)
  2091.             end
  2092.        
  2093.             local brakingStr = timeToBrakingStr or distanceToBrakingStr
  2094.        
  2095.             local stateHtml = not targetDest and getDestinationSelectionHtml() or ""
  2096.             local screenHtml = [[
  2097.               <style>
  2098.                 .space-autopilot-hud {
  2099.                   position: fixed;
  2100.                   left: 3vw;
  2101.                   top: 5vh;
  2102.                   margin: 0;
  2103.                   padding: 0;
  2104.                   font-size: 1.5vh;
  2105.                 }
  2106.                 .space-autopilot-hud span {
  2107.                   font-family: Consolas, monospace;
  2108.                 }
  2109.               </style>
  2110.               <div class="space-autopilot-hud">
  2111.               <strong>Basic space autopilot</strong><br>
  2112.               <span>]] .. versionStr .. [[</span><br>
  2113.               <br>
  2114.               Velocity: <span>]] .. rfuVelocityStr .. [[ m/s</span><br>
  2115.               Speed: <span>]] .. speedStr .. [[ km/h</span><br>
  2116.               Drift: <span>]] .. driftLenStr .. [[ km/h</span><br>
  2117.               <br>
  2118.               Gravity: <span>]] .. gravityStr .. [[ m/s<sup>2</sup></span><br>
  2119.               <br>
  2120.               Velocity to target: <span>]] .. radiansToTargetVelocityStr .. [[&deg;</span><br>
  2121.               Forward to target: <span>]] .. radiansToForwardAlignmentStr .. [[&deg;</span><br>
  2122.               Vertical to drift: <span>]] .. radiansToDriftStr .. [[&deg;</span><br>
  2123.               <br>
  2124.               Destination: <span>]] .. selectedDestStr .. [[</span><br>
  2125.               Distance: <span>]] .. distanceToDestStr .. [[</span><br>
  2126.               Braking in: <span>]] .. brakingStr .. [[</span><br>
  2127.               <br>
  2128.               Started braking: <span>]] .. tostring(startedBraking) ..[[</span><br>
  2129.               Arrived: <span>]] .. tostring(arrived) .. [[</span><br>
  2130.               <br>
  2131.               ]] .. stateHtml .. [[</div>]]
  2132.             system.setScreen(screenHtml)
  2133.           end
  2134.        
  2135.           local script = {} ---@class BasicSpaceAutopilotScript
  2136.        
  2137.           function script.onStart ()
  2138.             control.hide()
  2139.        
  2140.             system.showScreen(1)
  2141.             updateScreen()
  2142.        
  2143.             screenUpdateTimer.onStart()
  2144.           end
  2145.        
  2146.           function script.onStop ()
  2147.             system.showScreen(0)
  2148.             system.setScreen("")
  2149.        
  2150.             screenUpdateTimer.onStop()
  2151.           end
  2152.        
  2153.           ---@param action string
  2154.           function script.onActionStart (action)
  2155.             if targetDest ~= nil or not checkAutopilotForDeparture() then return end
  2156.        
  2157.             if action == selectPrevAction then
  2158.               destSwitcher.switchToPrevious()
  2159.             elseif action == selectNextAction then
  2160.               destSwitcher.switchToNext()
  2161.             elseif action == confirmSelectionAction then
  2162.               local dest = destSwitcher.getCurrent()
  2163.        
  2164.               local posNearDest = getPosNearDestination(dest)
  2165.               if not posNearDest then return end
  2166.        
  2167.               targetPos = posNearDest
  2168.               targetDest = dest
  2169.             end
  2170.        
  2171.             updateScreen()
  2172.           end
  2173.        
  2174.           function script.onFlush ()
  2175.             flight.onBeforeFlush()
  2176.        
  2177.             rfuVelocity = vec3(coordConverter.relWorldToRightForwardUp(state.worldVelocity))
  2178.        
  2179.             driftLen = nil
  2180.        
  2181.             distanceToDest = nil
  2182.             distanceToBraking = nil
  2183.        
  2184.             radiansToTargetVelocity = nil
  2185.             radiansToDrift = nil
  2186.             radiansToForwardAlignment = nil
  2187.        
  2188.             if not targetDest or arrived then
  2189.               local brakingAcceleration = vec3.zero
  2190.               if arrived or state.velocityMagnitude < maxSpeed * 0.5 then
  2191.                 brakingAcceleration = brakingAcceleration + flight.composeBrakingAccelerationAgainstGravity()
  2192.               end
  2193.               if arrived then
  2194.                 brakingAcceleration = brakingAcceleration + flight.composeBrakingAccelerationAgainstVelocity()
  2195.               end
  2196.        
  2197.               if state.atmosphereDensity > 0.8 then -- prevent adjustors from firing when the construct is probably landed
  2198.                 flight.setEngineTorqueCommand("torque", vec3.zero)
  2199.               else
  2200.                 flight.setEngineTorqueCommand('torque', flight.composeAngularAccelerationForAngularVelocity(vec3.zero), true)
  2201.               end
  2202.        
  2203.               flight.setEngineForceCommand("thrust analog", vec3.zero, false)
  2204.               flight.setEngineForceCommand("brake", brakingAcceleration, false)
  2205.        
  2206.               return
  2207.             end
  2208.        
  2209.             local constructToTargetPos = targetPos - state.constructWorldPos
  2210.             local constructToTargetPosLen = constructToTargetPos:len()
  2211.             local constructToTargetPosDir = constructToTargetPos / constructToTargetPosLen
  2212.        
  2213.             -- compute target speed for each axis
  2214.        
  2215.             local targetVelocity = constructToTargetPosDir * maxSpeed
  2216.             radiansToTargetVelocity = targetVelocity:angle_between(state.worldVelocity)
  2217.        
  2218.             local drift = state.worldVelocity:project_on_plane(targetVelocity)
  2219.             driftLen = drift:len()
  2220.             radiansToDrift = state.constructWorldOrientationUp:angle_between(-drift)
  2221.        
  2222.             local rfuTargetVelocity = vec3(coordConverter.relWorldToRightForwardUp(targetVelocity))
  2223.             local targetLateralSpeed = rfuTargetVelocity.x
  2224.             local targetVerticalSpeed = rfuTargetVelocity.z
  2225.             local targetLongitudinalSpeed = not startedBraking and rfuTargetVelocity.y or nil
  2226.        
  2227.             -- check braking distance
  2228.        
  2229.             do
  2230.               distanceToDest = constructToTargetPosLen
  2231.        
  2232.               local speedToDest = state.worldVelocity:project_on(constructToTargetPos):len()
  2233.               if state.worldVelocity:dot(constructToTargetPos) < 0 then speedToDest = speedToDest * -1 end
  2234.        
  2235.               local brakeForce = flight.getMaxBrakeForce() * maxBrakeForceSafetyMultiplier
  2236.               local brakingTime = estimateBrakingTime(-brakeForce, state.constructMass, state.velocityMagnitude, 0)
  2237.               local brakingDistance = estimateBrakingDistance(-brakeForce, state.constructMass, state.velocityMagnitude, brakingTime)
  2238.        
  2239.               distanceToBraking = distanceToDest - speedToDest * extraSecondsToStop - brakingDistance
  2240.        
  2241.               arrived = startedBraking and (
  2242.                 distanceToDest < 100 or
  2243.                 radiansToTargetVelocity > 90 * deg2rad
  2244.               )
  2245.             end
  2246.        
  2247.             -- compute braking acceleration
  2248.        
  2249.             local brakingAcceleration = vec3.zero
  2250.             if distanceToBraking <= 0 then
  2251.               startedBraking = true
  2252.               brakingAcceleration = flight.composeBrakingAccelerationAgainstVelocity()
  2253.             elseif not startedBraking then
  2254.               brakingAcceleration = flight.composeBrakingAccelerationToSpeed(state.speed, maxSpeed) -- brake if moving backward
  2255.        
  2256.               -- reduce forward speed if velocity is not aligned with target
  2257.               if rfuVelocity.y > maxSpeed * 0.95 and radiansToTargetVelocity > 2 * deg2rad then
  2258.                 brakingAcceleration = flight.composeBrakingAccelerationToSpeed(rfuVelocity.y, maxSpeed * 0.95)
  2259.               end
  2260.        
  2261.               -- greatly reduce speed if drifting a lot
  2262.               if state.velocityMagnitude > maxSpeed * 0.5 and driftLen > 2500 * KM_H_TO_M_S then
  2263.                 brakingAcceleration = flight.composeBrakingAccelerationToSpeed(state.velocityMagnitude, maxSpeed * 0.5)
  2264.               end
  2265.             end
  2266.        
  2267.             -- compute engine acceleration
  2268.        
  2269.             local lateralAcceleration =
  2270.               flight.composeAxisAccelerationToSpeed(state.constructOrientationRight, state.constructWorldOrientationRight, false, rfuVelocity.x, targetLateralSpeed) +
  2271.               flight.composeAxisLiftAcceleration(state.constructWorldOrientationRight)
  2272.        
  2273.             local verticalAcceleration = flight.composeAxisLiftAcceleration(state.constructWorldOrientationUp)
  2274.             if radiansToDrift < 30 * deg2rad or radiansToDrift > (180 - 30) * deg2rad then
  2275.               verticalAcceleration = verticalAcceleration +
  2276.                 flight.composeAxisAccelerationToSpeed(state.constructOrientationUp, state.constructWorldOrientationUp, false, rfuVelocity.z, targetVerticalSpeed)
  2277.             end
  2278.        
  2279.        
  2280.             local longitudinalAcceleration = flight.composeAxisLiftAcceleration(state.constructWorldOrientationForward)
  2281.             if targetLongitudinalSpeed then
  2282.               local shouldStopAcceleratingForward = state.speed > maxSpeed * 2/3 and driftLen > 10 * KM_H_TO_M_S
  2283.               if not shouldStopAcceleratingForward then
  2284.                 longitudinalAcceleration = longitudinalAcceleration +
  2285.                   flight.composeAxisAccelerationToSpeed(state.constructOrientationForward, state.constructWorldOrientationForward, true, rfuVelocity.y, targetLongitudinalSpeed)
  2286.               end
  2287.             end
  2288.        
  2289.             -- compute angular acceleration
  2290.        
  2291.             local forwardAlignmentAngularVelocity
  2292.             local verticalAlignmentAngularVelocity
  2293.        
  2294.             local alignmentSpeedFactor = clamp(rangeMap(state.velocityMagnitude, maxSpeed * 0.6, maxSpeed, 1, 0.2), 0.2, 1)
  2295.             local driftCorrectionFactor = clamp(rangeMap(driftLen, 0.1 * KM_H_TO_M_S, 10 * KM_H_TO_M_S, 0, 1), 0, 1)
  2296.        
  2297.             forwardAlignmentAngularVelocity, radiansToForwardAlignment = flight.composeAngularVelocityForAxisAlignment(
  2298.               state.constructWorldOrientationForward,
  2299.               targetVelocity,
  2300.               alignmentSpeedFactor)
  2301.        
  2302.             verticalAlignmentAngularVelocity = flight.composeAngularVelocityForAxisAlignment(
  2303.               state.constructWorldOrientationUp,
  2304.               -drift * 1 - state.worldGravity * 15 + state.constructWorldOrientationUp * 2,
  2305.               alignmentSpeedFactor * driftCorrectionFactor)
  2306.        
  2307.             local angularVelocity = forwardAlignmentAngularVelocity + verticalAlignmentAngularVelocity:project_on(state.constructWorldOrientationForward)
  2308.             local angularAcceleration = flight.composeAngularAccelerationForAngularVelocity(angularVelocity)
  2309.        
  2310.             -- apply thrust and torque to engines
  2311.        
  2312.             flight.setEngineForceCommand("brake", brakingAcceleration, false)
  2313.        
  2314.             flight.setEngineForceCommand("thrust analog lateral", lateralAcceleration, true)
  2315.             flight.setEngineForceCommand("thrust analog longitudinal", longitudinalAcceleration, true)
  2316.             flight.setEngineForceCommand("thrust analog vertical", verticalAcceleration, true)
  2317.        
  2318.             flight.setEngineTorqueCommand('torque', angularAcceleration, true)
  2319.           end
  2320.        
  2321.           function script.onUpdate()
  2322.             if screenUpdateTimer.ticked then
  2323.               screenUpdateTimer.ticked = false
  2324.               updateScreen()
  2325.             end
  2326.           end
  2327.        
  2328.           function script.onTick (timerId)
  2329.             screenUpdateTimer.onTick(timerId)
  2330.           end
  2331.        
  2332.           return script
  2333.         end
  2334.        
  2335.         return { new = createScript }
  2336.        
  2337.         end
  2338.         end
  2339.        
  2340.         end
  2341.        
  2342.         local CompositeComponent = require "pilot.components.CompositeComponent"
  2343.         local DefaultWidgetComponent = require "pilot.components.DefaultWidgetComponent"
  2344.         local Script = require "scripts.flight-space-autopilot.Script"
  2345.         local Hal = require "du.Hal"
  2346.        
  2347.         local control = Hal.requireControl()
  2348.         local core = Hal.requireDynamicCore()
  2349.         local system = Hal.requireSystem()
  2350.        
  2351.         script = CompositeComponent.new {
  2352.           Script.new(control, core, system),
  2353.           DefaultWidgetComponent.new(system, {
  2354.             {
  2355.               panelLabel = "Core",
  2356.               widgetType = "core",
  2357.               elements = { core }
  2358.             },
  2359.             {
  2360.               panelLabel = "Space Fuel",
  2361.               widgetType = "fuel_container",
  2362.               elements = Hal.getElementsWithClass(Hal.classes.SpaceFuelContainer)
  2363.             }
  2364.           })
  2365.         }
  2366.         script.onStart()
  2367.         --------------------------------------------------------------------------------
  2368.         -- basic space autopilot bundle ends
  2369.         --------------------------------------------------------------------------------
  2370.        
  2371.        
  2372.         -- error handling code added by wrap.lua
  2373.         end, __wrap_lua__traceback)
  2374.         if not ok then
  2375.           __wrap_lua__error(message)
  2376.           if not script then script = {} end
  2377.         end
  2378.     stop:
  2379.       lua: |
  2380.        if not __wrap_lua__stopped and script.onStop then
  2381.           local ok, message = xpcall(script.onStop,__wrap_lua__traceback,unit)
  2382.           if not ok then __wrap_lua__error(message) end
  2383.         end
  2384.     tick(timerId):
  2385.       lua: |
  2386.        if not __wrap_lua__stopped and script.onTick then
  2387.           local ok, message = xpcall(script.onTick,__wrap_lua__traceback,timerId,unit)
  2388.           if not ok then __wrap_lua__error(message) end
  2389.         end
  2390.   system:
  2391.     actionStart(action):
  2392.       lua: |
  2393.        if not __wrap_lua__stopped and script.onActionStart then
  2394.           local ok, message = xpcall(script.onActionStart,__wrap_lua__traceback,action,system)
  2395.           if not ok then __wrap_lua__error(message) end
  2396.         end
  2397.     actionStop(action):
  2398.       lua: |
  2399.        if not __wrap_lua__stopped and script.onActionStop then
  2400.           local ok, message = xpcall(script.onActionStop,__wrap_lua__traceback,action,system)
  2401.           if not ok then __wrap_lua__error(message) end
  2402.         end
  2403.     actionLoop(action):
  2404.       lua: |
  2405.        if not __wrap_lua__stopped and script.onActionLoop then
  2406.           local ok, message = xpcall(script.onActionLoop,__wrap_lua__traceback,action,system)
  2407.           if not ok then __wrap_lua__error(message) end
  2408.         end
  2409.     update:
  2410.       lua: |
  2411.        if not __wrap_lua__stopped and script.onUpdate then
  2412.           local ok, message = xpcall(script.onUpdate,__wrap_lua__traceback,system)
  2413.           if not ok then __wrap_lua__error(message) end
  2414.         end
  2415.     flush:
  2416.       lua: |
  2417.        if not __wrap_lua__stopped and script.onFlush then
  2418.           local ok, message = xpcall(script.onFlush,__wrap_lua__traceback,system)
  2419.           if not ok then __wrap_lua__error(message) end
  2420.         end