minetest_modding_book/_en/basics/lua.md
2024-10-23 00:39:22 +01:00

5.2 KiB

title layout root idx description redirect_from
Lua Scripting default ../.. 1.2 A basic introduction to Lua, including a guide on global/local scope. /en/chapters/lua.html

Introduction

In this chapter, you'll learn about scripting in Lua, the tools required to help with this, and some techniques that you may find useful.

Programming

Programming is the action of taking a problem, such as sorting a list of items, and turning it into steps that a computer can understand. Teaching you the logical process of programming is beyond the scope of this book; however, the following websites are quite useful in developing this:

  • Codecademy is one of the best resources for learning to write code. It provides an interactive tutorial experience.
  • Scratch is a good resource for starting from absolute basics, and learning the problem-solving techniques required to program. It's great for children and teenagers.
  • Programming with Mosh is a good YouTube series to learn programming.

Coding in Lua

It's also beyond the scope of this book to teach Lua coding. The Programming in Lua (PiL) book is an excellent introduction to Lua programming.

Code Editors

A code editor with code highlighting is sufficient for writing scripts in Lua. Code highlighting uses different colours for words and characters depending on what they represent. This allows you to easily notice mistakes and inconsistencies.

For example:

function ctf.post(team,msg)
    if not ctf.team(team) then
        return false
    end
    if not ctf.team(team).log then
        ctf.team(team).log = {}
    end

    table.insert(ctf.team(team).log,1,msg)
    ctf.save()

    return true
end

Keywords in this example are highlighted, including if, then, end, and return. Functions which come with Lua by default, such as table.insert, are also highlighted.

Commonly used editors which are well-suited for Lua include:

Other suitable editors are also available.

Local and Global Scope

Whether a variable is local or global determines where it can be written to or read from. Global variables can be accessed from anywhere in the script file, and from any other mod:

function one()
    foo = "bar"
end

function two()
    print(dump(foo))  -- Output: "bar"
end

one()
two()

In constrast, a local variable is only accessible from where it is defined. Lua defaults to variables being global, so you need to explicitly use the local keyword:

-- Accessible from within this script file
local one = 1

function myfunc()
    -- Accessible from within this function
    local two = one + one

    if two == one then
        -- Accessible from within this if statement
        local three = one + two
    end
end

Locals should be used as much as possible

Local variables should be used whenever possible. Mods should only create one global at most, with the same name as the mod. Creating other globals is sloppy coding, and Minetest will warn about this:

Assignment to undeclared global 'foo' inside function at init.lua:2

To correct this, use "local":

function one()
    local foo = "bar"
end

function two()
    print(dump(foo))  -- Output: nil
end

one()
two()

Remember that nil means not initialised. The variable hasn't been assigned a value yet, doesn't exist, or has been uninitialised (meaning set to nil).

Functions are variables of a special type, but should also be made local, because other mods could have functions with the same names.

local function foo(bar)
    return bar * 2
end

To allow mods to call your functions, you should create a table with the same name as the mod and add your function to it. This table is often called an API table or namespace.

mymod = {}

function mymod.foo(bar)
    return "foo" .. bar
end

-- In another mod, or script:
mymod.foo("foobar")

function mymod.foo() is equivalent to mymod.foo = function(), it's just a nicer way to write it.

Including other Lua Scripts

The recommended way to include other Lua scripts in a mod is to use dofile.

dofile(core.get_modpath("modname") .. "/script.lua")

A script can return a value, which is useful for sharing private locals:

-- script.lua
local module = {}
module.message = "Hello World!"
return module

-- init.lua
local ret = dofile(core.get_modpath("modname") .. "/script.lua")
print(ret.message) -- Hello world!

Later chapters will discuss how best to split up code for a mod.