the basic API of the computer is described here, which is available in a global environment
all methods of this API are available to the computer by default


_G / _ENV - link to the global computer environment(not the global environment of the mod, which is available via global in unsafe mode, but the global environment of the script)


sm - link to scrap mechanic api: safe mode | unsafe mode


global - link to global namespace (unsafe mode only)


self - link to ScriptableComputer script (unsafe mode only)


require(libraryName:string):table - gets access to the library with the specified name


isBetterAPI():boolean - returns true if betterAPI is installed and false otherwise


class(parent:class):class - this method allows you to do something like OOP in lua

                --class usage
local display = getComponent("display")
display.reset()
display.clear()

-- ball class
local ballClass = class()

function ballClass:init()
    self.x = math.random(0, display.getWidth() - 1)
    self.y = math.random(0, display.getHeight() - 1)
    self.dx = math.random() - 0.5
    self.dy = math.random() - 0.5
    self.color = sm.color.new(math.random(), math.random(), math.random())
end

function ballClass:tick()
    self.x = self.x + self.dx
    self.y = self.y + self.dy
    if self.x <= 0 or self.x >= display.getWidth() - 1 then self.dx = -self.dx end
    if self.y <= 0 or self.y >= display.getHeight() - 1 then self.dy = -self.dy end
end

function ballClass:draw()
    display.fillCircle(self.x, self.y, 15, self.color)
end

-- create balls
local balls = {}

for i = 1, 10 do
    local ball = ballClass()
    ball:init()
    table.insert(balls, ball)
end

function callback_loop()
    if _endtick then
        display.clear()
        display.flush()
        return
    end

    display.clear()
    for i, ball in ipairs(balls) do
        ball:tick()
        ball:draw()
    end
    display.flush()
end
            


checkArg(argnum, arg, ...) - checks the correctness of the arguments

                --checkArg usage
function test(num)
    checkArg(1, num, "number", "nil")
    if num ~= nil then
        return num + 1
    end
    return true
end
test(1)    --ok
test(4)    --ok
test(-111) --ok
test(nil)  --ok
test("a")  --error: 

function callback_loop() end
            


print(...) - displays a message in the chat (make sure that "Allow Chat/Alert/Debug Messages" is enabled in the Permission Tool)


alert(...) - it works exactly the same as print but outputs messages from the top of the screen (make sure that "Allow Chat/Alert/Debug Messages" is enabled in the Permission Tool)


debug(...) - outputs a message to the game's debugging console (works only when developer mode -dev is enabled) (make sure that "Allow Chat/Alert/Debug Messages" is enabled in the Permission Tool)


log(...) - outputs a message to the debugging console in the computer GUI (it always works, does not require to be enabled in the mod settings)


logPrint(...) - outputs a message to the game chat if the mod settings allow it and always outputs this message to the internal debugging console of the computer (even if it is impossible to output a message to the chat)


warning(msg) - outputs a warning to the debugging console in the computer GUI (it always works, does not require to be enabled in the mod settings)


unpack(table):... - decompresses the table into values


tostring(v) - see[www.lua.org/manual/5.1]


tonumber(str) - see[www.lua.org/manual/5.1]


clearregs() - clear all registers


getreg(name: str) -> [number | bool] - get value from register (the value can be written to the register using the composite writer)


setreg(name: str, value: [number | bool]) - set value to register (the value can be read from the register using the composite reader)


type(val) - see[www.lua.org/manual/5.1]


assert(cond: bool, msg: [str | nil]) - see[www.lua.org/manual/5.1]


error(msg, level: [num | nil]) - see[www.lua.org/manual/5.1]


pairs(table) -> (function, value, nil) - see[www.lua.org/manual/5.1]


ipairs(table) -> (function, value, 0) - see[www.lua.org/manual/5.1]


next(table, index) -> (index, value) - see[www.lua.org/manual/5.1]


pcall(f, ...) -> (num, ...) - see[www.lua.org/manual/5.1]


xpcall(f, err) -> (num, result) - see[www.lua.org/manual/5.1]


select(index, ...) -> ... - see[www.lua.org/manual/5.1]


getParentComputers() -> table - returns table of parent computers data


getChildComputers() -> table - returns table of child computers data


getCurrentComputer() -> table - returns table of self computer data


getComponent(name) -> table - returns the api table of the first connected component of the specified type. creates an exception if a component of this type is not connected


getComponents(name) -> table - returns a table with api tables of all connected components of the specified type


getMotorByLabel(label:string) -> table - returns motor by label, if there is no motor with such label, it will return an exception


getMotorsByLabel(label:string) -> table - returns a table of motors with the specified label


getComponentByLabel(componentType:string, label:string) -> table - returns component by label, if there is no component with such label, it will return an exception


getComponentsByLabel(componentType:string, label:string) -> table - returns a table of components with the specified label


clientInvoke(code: str, args...) - performs invokation some code on clients (unsafe mode only)


clientInvokeTo(player_nickname/playerobj, code: str, args...) - performs invokation some code on client (unsafe mode only)


serverInvoke(code: str, args...) - calls the code on the server side from the client. available only from the code executed from clientInvoke (unsafe mode only)


input(color: [smcolor | string | number | nil]) -> bool - input selector (if color specified); returns true if one on selected inputs is true else returns false


ninput(color: [smcolor | string | number | nil]) -> table[num] - if color specified returns table of parent interactable powers; if no color - returns full table of powers


out(value: [num | bool]) - set power and active state of self.interactable


loadstring(code: str, env: table|nil) -> function - make function from code


load(chunk, chunkname, mode, lenv) -> function - make function from code (alternative to loadstring, works identically)


execute(code: str, env: table|nil) - execute string code


getDeltaTime():number - returns the deltatime between game frames


getDeltaTimeTps():number - returns the deltatime between game ticks


reboot() - restarts the computer. however, it does not interrupt the execution of the current block of code. the reboot will happen only after the computer completes the tick code. please note that if the computer often shut down in a short period of time due to a "too long without yielding" error, then you will not be able to restart it programmatically or by giving a logical signal through the "reboot gate" this was done to prevent the creation of lag machines


getMaxAvailableCpuTime():number - returns the maximum time that you can stay in the loop for 1 game tick. however, you cannot use all the processor time every tick, as this will lead to an increase in the lag score counter and as a result, your computer will start skipping ticks and may crash


getSkippedTicks():number - returns the number of ticks that your computer has missed since the previous receipt of control. normally, this method should always return 0, if these values sometimes become greater than 0, you should optimize your code


getLagScore():number - the lag counter. if your computer creates lags, then this value will increase. if this value reaches 10, then your computer will start skipping clock cycles in order to avoid game lags. if this value reaches 100, your computer will crash. if your computer has stopped creating lags, then this value will be deducted at 1 per tick


getUptime():number - returns the computer's running time in game ticks(40 ticks - one second). if the computer skips ticks to using too much processor time, this function will still show the real time of operation. this means that the value can change by more than 1 (if your computer missed a tick)


getTick():number - it works almost the same as getUptime, but it cannot increase by more than 1 in one iteration, even if the computer skips several tick, this variable will never jump by more than one value. thus, if you make a "getUptime() - getTick()", you will get the number of missed tick for the entire time of operation


getDeviceType():string - returns the type of your computer. it can be "computer" or "tablet" (tablets are not available at the moment)


isComponentAvailable(componentTable:table):boolean - checks whether this component is available for circulation (that is, whether it is connected to the computer, and that it has not yet been blown up)

                --isComponentAvailable usage
local display = getComponent("display")

function callback_loop()
    if not isComponentAvailable(display) then
        print("component not available")
        return
    end
    display.clear(sm.color.new(math.random(), math.random(), math.random()))
    display.flush()
end
            


setComponentApi(name:string, api:table) - makes your computer pretend to be components for other computers. call this function without arguments to cancel the API

                --setComponentApi usage
--makes a holographic display from a holographic projector (in fact, you'd better use a separate part of the holographic display for this)
local vdisplay = require("vdisplay")
local holo = getComponent("holoprojector")
holo.reset()
holo.clear()
holo.flush()

local width, height = 32, 32
local idBuffer = {}

local callbacks = {
    set = function (self, x, y, color)
        local index = x + (y * width)
        if idBuffer[index] then holo.delVoxel(idBuffer[index]) end
        idBuffer[index] = holo.addVoxel(x - (width / 2), (((height - 1) - y) - (height / 2)) + 20, 0, color, 2)
    end,
    flush = function (self, isForce)
        holo.flush()
    end
}
setComponentApi("display", vdisplay.create(callbacks, width, height)) --this line will cause your computer to be identified by other computers as a display

function callback_loop()
    if _endtick then
        holo.reset()
        holo.clear()
        holo.flush()
        return
    end

    callbacks.update()

    --[[ an example of simulated clicks
    callbacks.pushClick({0, 0, "pressed", 1})
    callbacks.pushClick({0, 0, "released", 1})
    ]]

    --[[ if you know that someone is not looking at your screen now, then it is better to inform the library about it
    if mySecretSource_thereIsNoOneAround then
        callbacks.updateAudience(0)
    else
        callbacks.updateAudience(1)
    end
    ]]
end
            


getComponentApi():name, api - returns what was set using setComponentApi


setLock(state:boolean) - set the flag to true so that the user cannot open the computer UI


getLock():state - returns what was set using setLock


setInvisible(state:boolean) - set the invisibility flag so that your computer cannot be detected using getParentComputers and getChildComputers (you can still transfer data using setComponentApi)


getInvisible():state - returns what was set using setInvisible

            --setLock & setInvisible & setComponentApi using
--the invisibility flag makes it so that other computers cannot see this computer using the getParentComputers and getChildComputers methods
--this is necessary in order to protect the computer from direct external interference
--let's say you have blocked the computer's GUI. the computer code can still be read and written using another computer
--to protect against this, there is an invisibility flag
--if you need to protect your code from direct reading/writing to ENV, but you need to communicate with other computers,
--then you can use the network port or use the setComponentApi method so that your computer simulates the behavior
--of the component and your API is accessible via getComponents

--now you will not be able to interact with this computer using getParentComputers and getChildComputers
setInvisible(true)
--now you can't open the gui of the computer
setLock(true)

setComponentApi("tunnel", {
    unlock = function()
        --my unlock condition
        setInvisible(false)
        setLock(false)
    end
})

--to unlock it, you can now use the following code on another
--this is somewhat similar to unlocking the bootloader on Xiaomi phone
--[[
local tunnel = getComponent("tunnel")
tunnel.unlock()

function callback_loop()
    
end
]]

--if the invisibility flag is not set, then it would be possible to unlock the computer bypassing your API with your checks
--[[
for _, computer in ipairs(getParentComputers()) do
    computer.env.setLock(false)
end

for _, computer in ipairs(getChildComputers()) do
    computer.env.setLock(false)
end
]]

function callback_loop()
    
end
        

setCode(code:string) - overwrites the computer code but does not restart it.
please note that if you had code encryption enabled, then after using this method, the code will no longer be encrypted. If you need to update the code so that it remains encrypted, you need to call encryptCode() immediately after this method.


getCode():string - returns the current computer code
please note that if the code is encrypted, this method will return a comment for the user, which indicates that the code is encrypted, it will not return the real code or its encrypted form
to avoid UB, before using this method, it is better to insert a check that the code is encrypted using isCodeEncrypted()


setEncryptedCode(bytecode:string, string|nil) - sets the encrypted code, which can be obtained from the enlua library. it can be used to receive OTA updates in encrypted form. the second argument is a comment for the user that can be set for the encrypted code
the changes will take effect after the reboot(you can trigger a software reboot) can be used, for example, to update the code through the antenna.


encryptCode(string|nil):boolean - encrypts the code if it is not encrypted and does nothing if the code is already encrypted.
this action cannot be undone except by overwriting the encrypted code to a new version of the code use setCode() / setEncryptedCode()
this method does not restart the computer.
you can pass a string here as a message for the user who opens the computer with the encrypted code. these message cannot be changed after the code is already encrypted, even if you call this method again.
returns true if the code was encrypted, returns false if it was already encrypted at the time of the call or it could not be encrypted for some reason.


isCodeEncrypted():boolean - returns true if the code was encrypted.


setData(string) - sets the data string of the computer, it is written to the computer block and can be read using getData. the maximum size of this string is 4 kilobytes


getData():string - returns the current string of computer data


setTable(table) - serializes the table and writes it via setData, the total size of the serialized table should not exceed 4 kilobytes


getTable():table - tries to deserialize a string from getData as json. if this is not possible it will return an empty table


setAlwaysOn(state:boolean) - sets the always on flag, after installing it, the computer will work without giving a logical signal


getAlwaysOn():boolean - returns the status of the always on flag



flags


_endtick - this is the value that will be set to true in your _ENV if this is the last iteration of this computer


_enableCallbacks - set this value to true in your _ENV if you want to use alternative callbacks


_disableBsod - if you set this flag to _ENV, the computer will not display an error message on all connected screens and terminals when crashing


callbacks (_enableCallbacks: true)


onStart() - called when your computer performs the first iteration


onTick(dt:number) - every tick is called. dt in this case is the deltatime of TPS multiplied by the number of skipped ticks by the computer + 1


onStop() - called when your computer does the last iteration


onError(error:string):boolean - called in case of an error during code execution. after performing this function, the computer will crash anyway, return true if you want the computer to reboot after that (in this case you will not receive an error message)

            --the code written here is executed only 1 time when the computer is turned on

function onStart()
    --the code written here is executed after the code written outside the function
end

function onTick(dt)
    --the code written here will be executed every tick when the computer is turned on
    --dt in this case is the deltatime of TPS multiplied by the number of skipped ticks by the computer + 1
end

function onStop()
    --it is executed when you turn off the computer
end

function onError(err)
    --called if an error occurred in your code during execution
    --even though you have received an error, it will still cause your computer to crash
    --errors in the error handler can only be seen in the game console if you run it with the (-dev) flag

    --return true --return true if you want to restart the computer
end

_enableCallbacks = true
        

callbacks (_enableCallbacks: false)


callback_loop() - implement this function in your code and it will be an alternative entry point


callback_error(error:string):boolean - called in case of an error during code execution. after performing this function, the computer will crash anyway, if you do not want it, call reboot (in this case you will not receive an error message)

working with callbacks (old style)

            --the code written here is executed only 1 time when the computer is turned on

function callback_loop()
    if _endtick then
        --it is executed when you turn off the computer
        return
    end

    local dt = getDeltaTimeTps() * (getSkippedTicks() + 1)
    --the code written here will be executed every tick when the computer is turned on
    --dt in this case is the deltatime of TPS multiplied by the number of skipped ticks by the computer + 1
end

function callback_error(err)
    --called if an error occurred in your code during execution
    --even though you have received an error, it will still cause your computer to crash
    --errors in the error handler can only be seen in the game console if you run it with the (-dev) flag

    --reboot() --if you want to restart the computer
end
            
        

working without callbacks

            if _endtick then
    --it is executed when you turn off the computer
    return
end
            
if not started then
    --the code written here is executed only 1 time when the computer is turned on
    started = true
    return
end

local dt = getDeltaTimeTps() * (getSkippedTicks() + 1)
--the code written here will be executed every tick when the computer is turned on
--dt in this case is the deltatime of TPS multiplied by the number of skipped ticks by the computer + 1