But to write Lua scripts, some knowledge with the programming language Lua is required.
Minetest uses Lua 5.1. The reference document for Lua 5.1 is [here](https://www.lua.org/manual/5.1/). The book [Programming in Lua (first edition)](https://www.lua.org/pil/contents.html) is also a perfect source for learning Lua.
The Server block is used to store data from Lua Controllers nonvolatile. It can also be used for communication purposes between several Lua Controllers.
Only configured players have access to the server. Therefore, the server has a menu to enter player names.
The controller uses a subset of the language Lua, called SaferLua. It allows the safe and secure execution of Lua scripts, but has the following limitations:
- limited code length
- limited execution time
- limited memory use
- limited possibilities to call functions
SaferLua follows the standard Lua syntax with the following restrictions:
- no `while` or `repeat` loops (to prevent endless loops)
- no table constructor {..}, see "Arrays, Stores, and Sets" for comfortable alternatives
- limited runtime environment
SaferLua directly supports the following standard functions:
For own function definitions, the menu tab 'func' can be used. Here you write your functions like:
```lua
function foo(a, b)
return a + b
end
```
Each SaferLua program has access to the following system variables:
- ticks - a counter which increments by one each call of `loop()`
- elapsed - the amount of seconds since the last call of `loop()`
- event - a boolean flag (true/false) to signal the execution of `loop()` based on an occurred event
### Arrays, Stores, and Sets
It is not possible to easily control the memory usage of a Lua table at runtime. Therefore, Lua tables can't be used for SaferLua programs. Because of this, there are the following alternatives, which are secure shells over the Lua table type:
#### Arrays
_Arrays_ are lists of elements, which can be addressed by means of an index. An index must be an integer number. The first element in an _array_ has the index value 1. _Arrays_ have the following methods:
Unlike _arrays_, which are indexed by a range of numbers, _stores_ are indexed by keys, which can be a string or a number. The main operations on a _store_ are storing a value with some key and extracting the value given the key.
- keys(order) - return an _array_ with the keys. If _order_ is `"up"` or `"down"`, return the keys as sorted _array_, in order of the _store_ values.
Example:
```lua
s = Store("a", 4, "b", 5) --> {a = 4, b = 5}
s.set("val", 12) --> {a = 4, b = 5, val = 12}
s.get("val") --> returns 12
s.set(0, "hello") --> {a = 4, b = 5, val = 12, [0] = "hello"}
s.del("val") --> {a = 4, b = 5, [0] = "hello"}
s.size() --> function returns 3
s.memsize() --> function returns 9
for key,val in s.next() do
...
end
```
Keys sort example:
```lua
s = Store() --> {}
s.set("Joe", 800) --> {Joe=800}
s.set("Susi", 1000) --> {Joe=800, Susi=1000}
s.set("Tom", 60) --> {Joe=800, Susi=1000, Tom=60}
s.keys() --> {Joe, Susi, Tom}
s.keys("down") --> {Susi, Joe, Tom}
s.keys("up") --> {Tom, Joe, Susi}
```
#### Sets
A _set_ is an unordered collection with no duplicate elements. The basic use of a _set_ is to test if an element is in the _set_, e.g. if a player name is stored in the _set_.
The _set_ has the following methods:
- add(val) - add a value to the _set_
- del(val) - delete a value from the _set_
- has(val) - test if value is stored in the _set_
- size() - return the number of _set_ elements
- memsize() - return the needed _set_ memory space
All three types of data structures allow nested elements, e.g. you can store a _set_ in a _store_ or an _array_ and so on. But note that the overall size over all data structures can't exceed the predefined limit. This value is configurable for the server admin. The default value is 1000.
The configured limit can be determined via `memsize()`:
The TA4 Lua Controller distinguishes between the initialization phase (just after the controller was started) and the continuous operational phase, in which the normal code is executed.
During the initialization phase the function `init()` is executed once. The `init()` function is typically used to initialize variables, clean the display, or reset other blocks:
If an event occurs (a command was received from another block), the `loop()` is executed (in addition to the normal loop cycle). In this case the system variable 'event' is set:
-`$print(text)` - Output a text string on the 'outp' tab of the controller menu.
E.g.: `$print("Hello "..name)`
-`$loopcycle(seconds)` - This function allows to change the call frequency of the controller loop() function, witch is per default one second. For more info, see "Cyclic Task"
-`$events(bool)` - Enable/disable event handling. For more info, see "Events"
-`$time_as_str()` - Read the time of day (ingame) as text string in 24h format, like "18:45"
-`$time_as_num()` - Read the time of day (ingame) as integer number in 24h format, like 1845
-`$get_input(num)` - Read an input value provided by an external block with the given number _num_. The block has to be configured with the number of the controller to be able to send status messages (on/off commands) to the controller. _num_ is the number of the remote block, like "1234".
| "load" | number | Read the load value in percent (0..100) of a tank, silo, accu, or battery block, or from the Signs Bot Box. Silo and tank return two values: The percentage value and the absolute value in units.<br/> Example: percent, absolute = $send_cmnd("223", "load") |
| "count" | number of items | Read the total amount of TA4 chest items. An optional number as `add_data` is used to address only one inventory slot (1..8, from left to right). |
| "itemstring" | item string of the given slot | Specific command for the TA4 8x2000 Chest to read the item type (technical name) of one chest slot, specified via `add_data` (1..8).<br/>Example: s = $send_cmnd("223", "itemstring", 1) |
| "output" | recipe output string, <br/>e.g.: "default:glass" | Only for the Industrial Furnace. If no recipe is active, the command returns "unknown" |
| "limit" | number | Configure a TA4 Pusher with the number of items that are allowed to be pushed ("flow limiter" mode)<br/>limit = 0 turns off the "flow limiter" mode |
| "limit" | number | Configure a TA4 Pump with the number of liquid units that are allowed to be pumped ("flow limiter" mode)<br/>limit = 0 turns off the "flow limiter" mode |
| "exchange" | inventory slot number | TA3 Door Controller II (techage:ta3_doorcontroller2)<br/>Exchange a block<br/>*idx* is the inventory slot number (1..n) of/for the block to be exchanged |
| "set" | inventory slot number | TA3 Door Controller II (techage:ta3_doorcontroller2)<br/>Set/add a block<br/>*idx* is the inventory slot number (1..n) with the block to be set |
| "dig" | inventory slot number | TA3 Door Controller II (techage:ta3_doorcontroller2)<br/>Dig/remove a block<br/>*idx* is the empty inventory slot number (1..n) for the block |
| "move2" | x,y,z | TA4 Move Controller command to move the block(s) by the given<br/> x/y/z-distance. Valid ranges for x, y, and z are -100 to 100.<br/>Example: `$send_cmnd("1674", "move2", "0,4,0")` |
| "left" | nil | TA4 Turn Controller command to turn the block(s) to the left |
| "right" | nil | TA4 Turn Controller command to turn the block(s) to the right |
| "uturn" | nil | TA4 Turn Controller command to turn the block(s) 180 degrees |
| "recipe" | `<item_name>,<item_name>,...` | Set the TA4 Autocrafter recipe. <br/>Example for the torch recipe: `default:coal_lump,,,default:stick`<br/>Hint: Empty fields may only be left out at the end of the item list! |
| "recipe" | `<number>.<index>` | Set the TA4 Autocrafter recipe with a recipe from a TA4 Recipe Block.<br/>`<number>` is the TA4 Recipe Block number<br/>`<index>` is the number of the recipe in the TA4 Recipe Block |
| "goto" | `<slot>` | Start command for the TA4 Sequencer. `<slot>` is the time slot like `[1]` where the execution starts. |
| "stop" | nil | Stop command for the TA4 Sequencer. |
-`$server_write(num, key, value)` - Store a value on the server under the key _key_. _key_ must be a string. _value_ can be either a number, string, boolean, nil or data structure.
**This function does not allow nested data structures**.
Messages are used to transport data between Controllers. Messages can contain arbitrary data. Incoming messages are stored in order (up to 10) and can be read one after the other.
*`$get_msg([raw])` - Read a received message. The function returns the sender number and the message. (see example "Emails"). If the _raw_ parameter is not set or false, the message is guaranteed to be a string.
*`$display(num, row, text)` Send a text string to the display with number _num_. _row_ is the display row, a value from 1 to 5, or 0 to add the text string at the bottom (scroll screen mode). _text_ is the string to be displayed. If the first char of the string is a blank, the text will be horizontally centered.
*`$clear_screen(num)` Clear the screen of the display with number _num_.
*`$position(num)` Returns the position as string "'(x,y,z)" of the device with the given _num_.