Forks:Lua Examples

From LinuxWorks Minetest Server Wiki
Jump to navigation Jump to search

On this page you will find an introduction to programming a Lua Controller and some example Lua programs. Examples are added when they seem to be needed, so take a look at this page from time to time for new examples.

About the Lua Language

This is not an introduction to programming or Lua. For all informations about Lua please note that Minetest uses the version 5.1 of the Lua language.

A short introduction to the Lua Controller is avaiable at http://mesecons.net/luacontroller/ .

A good starting to point to get familiar with the Lua language is the page http://lua-users.org/wiki/LuaDirectory in the official wiki of the Lua language.

For easy reference, the Lua 5.1 Reference manual is excellent.

Fundamentals about Lua Controllers

The introduction at http://mesecons.net/luacontroller/ describes all important limitations of the Lua Controller compared to the use of Lua outside of Minetest.

As the website contains several mistakes here a short summary:

  • get the status of a port with x = pin.a (pin.b, ...)
  • set the status of a port with port.a = <status>
  • the 'print()' function writes into the server log, so it's not really usable, use LCDs or textlines as output
  • only one interrupt can be activated/stored, more calls to interrupt are ignored (This was changed to prevent lag)
  • you can send to one digiline address only one message, additional messages from more 'digiline_send()' to the same address are lost


This also needs to be considered:

  • the code in the Lua Controller is (more of less) only some sort of interrupt handler, not a complete program
  • write as efficient and simple as possible
  • interrupts with less than 1s are not allowed
  • hiding the code is not possible
  • Lua Controllers only run in loaded/active areas
  • commands must be in if..then code blocks with event-related conditions
  • your code will be audited by moderators, any problematic code will be disabled (see also "coding style")
  • LuaATC tracks and Operation Panels from advtrains are similar to code, but remember that they run always - even in unloaded areas


Programming a Lua Controller is not a good way to learn programming, as you need to know several programming concepts, we can't give tutorials or lessons. You need to know what the following terms or limitations are:

  • interrupts and interrupt handlers
  • no easy debugging possible
  • optimization of logic expressions
  • optimization by sorting the conditions by expected probability and a good experience to make good guesses about it

Coding Style

  • make your code easy to read
    • use indenting
    • no complex/long conditions for if
    • use descriptive variable names
    • add comments
  • don't recalculate values, save them in variables
  • put some thoughts into your code, make it as efficient as possible
  • when you have questions make sure you have really read all informations on this site, questions which are easily answered when reading this page can have serious repercussions

Examples

Blinking Lights

In case you need a configurable blinking light or a configurable timer for feeding any machines with items:

local time_on = 2   --  2 seconds on  
local time_off = 6  --  6 seconds off
  
if event.iid == "on" then
     port.a = true
     interrupt(time_on,"off")
     return
end

if event.iid == "off" then
     port.a = false
     interrupt(time_off,"on")
     return
end

if event.type == "program" then
     interrupt(1,"on")
     return
end

Code with comments.

Alternating two ports with switch

Port A and C will activate in alternation and it is switchable with a signal on port B.

local delay = 3

if event.iid == "c" then
     if not pin.b then return end
     port.a = not pin.a
     port.c = pin.a
     interrupt(delay,"c")
     return
end

if event.type == "on" then
     if event.pin.name == "B" then
          interrupt(1,"c")
     end
     return
end

if event.type == "program" then
     interrupt(1,"c")
     return
end

Display the server time

To display the current time and date of the server add an LCD (name: "lcd") to the Lua Controller and use this program:

local  lcd_name = "lcd"  

if event.iid == "d" then
     dt = os.datetable()
     tz_name = ((dt.isdst and "CEST") or "CET")
     outputtext = string.format("SERVER TIME | %4i-%02i-%02i | %02i:%02i %s", 
                                dt.year,dt.month,dt.day,dt.hour,dt.min,tz_name)
     digiline_send(lcd_name,outputtext)
     diff = 60 - dt.sec
     if diff<1 then diff=1 end
     if diff>30 then diff = 30 end
     interrupt(diff,"d")
     return
end

if event.type == "program" then
     digiline_send(lcd_name,"SERVER TIME | STARTING") 
     interrupt(1,"d")
     return
end

Code with comments.

Show mesecon input

To show the changes of the mesecon input lines:

local displayname = "lcd"

if event.type == "on" or event.type == "off" then
     local output = "Port " ..  event.pin.name .. ": " .. event.type
     digiline_send(displayname,output)
     return
end

The LCD shows the last change of any input line.

Execute commands when mesecon input changes

Use a counter with up and down and a reset.

local lcd = "lcd"

if event.type == "on" then
     if event.pin.name == "A" then
          mem.a = mem.a +1
          digiline_send(lcd,mem.a)
          return
     end
     if event.pin.name == "C" then
          mem.a = mem.a -1
          digiline_send(lcd,mem.a)
          return
     end
     if event.pin.name == "B" then
          mem.a = 0
          digiline_send(lcd,mem.a)
          return
     end
     return         
end


if event.type == "program" then
     mem.a = 0
     digiline_send(lcd,"START")
     return
end

Delayed Switch

Delay the switching off by a given delay:

-- detector/switch:  port D 
-- machine: port  A 

local  delay = 60

if event.type == "off" then
     if event.pin.name == "D" then
          interrupt(delay,"disable")
          return
     end
     return
end

if event.type == "on" then
     if event.pin.name == "D" then
          port.a = true
          return
     end
     return
end          

if event.iid == "disable" then
     if pin.d then return end
     port.a = false
     return
end

if event.type == "program" then
     if pin.d then 
          port.a = true
     end
     return  
end


Simple Uranium Enrichment

For an easy enrichment of uranium dust is only one centrifuge needed. This is not fast but a steady and reliable system.

local delay = 2
local injector = "eject"

if event.iid == "c" then
     digiline_send(injector,{ count = 2, exmatch = true, slotseq = "rotation" })
     interrupt(delay,"c")
     return
end

if event.type == "program" then
     interrupt(1,"c")
     return
end

Code with comments and a picture of the machine setup.

More Examples

Advtrains Examples

  • Enforce a minimal distance between trains
  • ...
  • ...

Lua Sorting Tube

The sorting tube will place a table event in your environment. It will have the field type. The tube has a special event type "item" for when an item enters the tube. The code should then return which side to output on as a colour string. The below code sorts three groups of items into three separate output sides, plus another side for unrecognised items. It is used in Blockhead's digtron facility.

Reference: VanessaE's pipeworks wiki page

local tailings = {
	"default:silver_sand",
	"default:gravel",
	"default:flint",
	"technic:granite",
	"technic:marble",
	"default:dirt",
	"default:bone"
}

local straights = {
	"default:coal_lump",
	"default:diamond",
	"default:mese",
	"default:mese_crystal",
}

local lumps = {
	"default:gold_lump",
	"moreores:silver_lump",
	"default:copper_lump",
	"default:iron_lump",
	"technic:zinc_lump",
	"moreores:mithril_lump",
	"technic:lead_lump",
	"default:tin_lump",
	"technic:chromium_lump"
}

local tailings_side  = "red"
local straights_side = "white"
local lumps_side     = "blue"
local unsorted_side  = "yellow"

if event.type == "item" then
	local name = event.item.name
	for _, v in pairs(tailings) do
		if name == v then return tailings_side end
	end
	for _, v in pairs(straights) do
		if name == v then return straights_side end
	end
	for _, v in pairs(lumps) do
		if name == v then return lumps_side end
	end
	return unsorted_side
end

Lua console shim

When debugging, using the luacontroller can be very frustrating, since it does not give a full stack trace. it is much easier to debug lua with a full stack trace, such as what you would get running Lua on the command line. However, since the luacontroller has its own API, you can't just simply paste luacontroller code and have it run correctly. What you can do, however, is put a 'shim' at the top of the file. This shim defines the environment that you need to run your luacontroller with, by defining key functions and tables like mem, event, digiline_send(channel, msg) and os.datetable(). You can still run the shimmed code in your singleplayer world or on linuxforks, but you will want to remove it after debugging so you can save time and space.

if not mem then mem = {} end
if event == nil then event = { type = "interupt"} end
if not digiline_send then digiline_send = function(channel, message)
  print(message)
end end
if not interrupt then
  interrupt = function(interval)
end end
if not os.datetable then os.datetable = function()
  return os.date("*t")
end end