Skip to content

Helpers

Helpers são um conjunto de funções auxiliares Lua para trabalho confortável no projeto.

Essas funções helper estendem significativamente as capacidades padrão do Lua e simplificam o desenvolvimento.


String

Métodos fornecidos pelo Luanti:

string:lower()

Converte string para minúsculas com suporte para cirílico.

lua
print(('ПРИВЕТ МИР'):lower())  -- 'привет мир'

string:upper()

Converte string para maiúsculas com suporte para cirílico.

lua
print(string.upper('привет мир'))  -- 'ПРИВЕТ МИР'

string:is_one_of(table)

Verifica se o string é um dos valores no array passado.
(Análogo semântico de table.contains, que verifica se o string está contido no array passado.)

lua
local text = 'hello'
local options = { 'hello', 'world', 'lua' }
print(text:is_one_of(options))  -- true

string:first_to_upper()

Converte a primeira letra para maiúscula.

lua
local text = 'hello world'
print(text:first_to_upper())  -- 'Hello world'

string :title()/:to_headline()

Converte a primeira letra de cada palavra para title case.
Nome alternativo: string:to_headline()

lua
local text = 'hello world from lua'
print(text:title())           -- 'Hello World From Lua'
print(text:to_headline())     -- 'Hello World From Lua'

string:starts_with(prefix)

Verifica se o string começa com o prefixo especificado.

lua
local filename = 'config.json'
print(filename:starts_with('config'))    -- true
print(filename:starts_with('settings'))  -- false

string:ends_with(suffix)

Verifica se o string termina com o sufixo especificado.

lua
local filename = 'config.json'
print(filename:ends_with('.json'))    -- true
print(filename:ends_with('.conf'))    -- false

string:contains(sub_string)

Verifica a presença de uma substring.

lua
local text = 'Hello, World !!!'
print(text:contains('World'))   -- true
print(text:contains('world'))   -- false (sensível a maiúsculas/minúsculas)

string:replace(pattern, replacement, n?)

Substitui substring (análogo de gsub, mas retorna apenas o string sem o número de substituições).
Veja documentação para string.gsub e Patterns

lua
local text = 'Hello, World, World!'
local result = text:replace('World', 'Lua')
print(result)  -- 'Hello, Lua, Lua!'

-- Substituir apenas a primeira ocorrência
local result2 = text:replace('World', 'Lua', 1)
print(result2)  -- 'Hello, Lua, World!'

string:remove(pattern, n?)

Remove substring.
Veja documentação para string.gsub e Patterns

lua
local text = 'Hello, World!'
print(text:remove(', '))        -- 'HelloWorld!'
print(text:remove('o', 1))      -- 'Hell, Wrld!' (remove apenas o primeiro 'o')

string:reg_escape()

Escapa caracteres especiais para expressões regulares.
Veja Patterns

lua
local pattern = 'file.txt'
print(pattern:reg_escape())      -- 'file%.txt'

local pattern2 = '^$()%.[]*+-?)'
print(pattern2:reg_escape())     -- '%^%$()%.%[%]%*%+\-%?)'

string:vxr_split(delimiter?, processor?)

Divide string pelo delimiter especificado com capacidade de processar partes.

Luanti tem seu próprio método string.split, mas não suporta processamento de partes.
Este método adiciona a capacidade de processar partes do string.

lua
-- Sem processamento
('hello world'):vxr_split()             -- { 'hello', 'world' }
('apple,banana,cherry'):vxr_split(',')  -- { 'apple', 'banana', 'cherry' }

-- Com processamento
local numbers = '1,2,3,4,5'
local squared = numbers:vxr_split(',', function(x)
    return tonumber(x)^2 
end)
print(squared[1], squared[2], squared[3], squared[4], squared[5])
-- 1 4 9 16 25

string.or_nil(value)

Converte para string ou retorna nil.

lua
print(string.or_nil('hello'))     -- 'hello'
print(string.or_nil(42))          -- '42'
print(string.or_nil(nil))         -- nil
print(tostring(nil))              -- 'nil' (comparação)

Métodos fornecidos pelo Luanti:

Luanti string.split()

Veja também: string.vxr_split(delimiter?, processor?)

Divide string em partes pelo separador especificado. Retorna array de strings. Argumentos:

  • separator? separador, padrão: ","
  • include_empty? padrão: false
  • max_splits? se negativo, divisões ilimitadas, padrão: -1
  • sep_is_pattern? se separador é string regular ou pattern (regex), padrão: false
lua
local text = 'apple,banana,cherry'
local parts = text.split(',')
print(parts[1], parts[2], parts[3])  -- 'apple', 'banana', 'cherry'

-- Dividir por espaços
local words = 'hello world lua'.split(' ')
print(words[1], words[2], words[3])  -- 'hello', 'world', 'lua'

Luanti string.trim()

Remove caracteres de espaço em branco no início e fim do string.

lua
print(("\n \t\tfoo bar\t "):trim())  -- 'foo bar'

Luanti string.pack()

Empacota valores em string binário de acordo com o formato.
Backport do Lua 5.4.

lua
-- Empacotar inteiros
local packed = string.pack('i4', 42)
print(#packed)  -- 4 (tamanho em bytes)

-- Empacotar múltiplos valores
local data = string.pack('i4f8', 100, 3.14)
print(#data)  -- 12 (4 + 8 bytes)

Luanti string.unpack()

Desempacota string binário em valores de acordo com o formato.
Backport do Lua 5.4.

lua
local packed = string.pack('i4f8', 100, 3.14)
local num, float, next_pos = string.unpack('i4f8', packed)
print(num, float)      -- 100, 3.14
print(next_pos)        -- 13 (posição após desempacotar)

-- Desempacotar da posição especificada
local value = string.unpack('i4', packed, 5)
print(value)            -- 3.14 (como float)

Luanti string.packsize()

Retorna o tamanho do string que será criado por string.pack.
Backport do Lua 5.4.

lua
local size = string.packsize('i4f8')
print(size)  -- 12 (4 + 8 bytes)

-- Para formatos complexos
local complex_size = string.packsize('i4c10f8')
print(complex_size)  -- 22 (4 + 10 + 8 bytes)

Table

Métodos, fornecidos pelo Luanti:

  • table.copy()
  • table.copy_with_metatables()
  • table.insert_all()
  • table.indexof()
  • table.keyof()
  • table.key_value_swap()
  • table.shuffle()

table.keys(table)

Retorna um array de chaves da tabela.

lua
local data = { name = 'Alek', age = 25, city = 'Vladivostok' }

local keys = table.keys(data)
-- `keys` contém `{ 'name', 'age', 'city' }` (ordem pode variar)

table.values(table)

Retorna um array de valores da tabela.

lua
local data = { name = 'Alek', age = 25, city = 'Vladivostok' }

local values = table.values(data)
-- `values` contém { 'Alek', 25, 'Vladivostok' }

table.has_key(table, key)

Verifica se uma chave existe na tabela.

lua
local data = { name = 'Alek', age = 25 }
print(table.has_key(data, 'name'))   -- true
print(table.has_key(data, 'city'))   -- false

table .contains/has_value(table, value)

Verifica se um valor existe na tabela.

lua
local fruits = { 'apple', 'banana', 'cherry' }
print(table.contains(fruits, 'banana'))  -- true
print(table.contains(fruits, 'orange'))  -- false

Você também pode usar string:is_one_of():

lua
print('banana':is_one_of(fruits))  -- true
print('orange':is_one_of(fruits))  -- false

Nome alternativo: table.has_value

lua
local data = { x = 10, y = 20 }
print(table.has_value(data, 10))     -- true
print(table.has_value(data, 30))     -- false

table.keys_of(table, value)

Retorna uma tabela com chaves da tabela especificada que têm o valor especificado.

lua
local data = { a = 10, b = 20, c = 10, d = 30 }
local keys = table.keys_of(data, 10)
print(dump(keys))  -- { 'a', 'c' }

local keys2 = table.keys_of(data, 99)
print(keys2)  -- nil (nenhuma chave assim)

table.has_any_key(table, find_keys)

Verifica se as chaves da tabela contêm pelo menos um valor do array especificado.

lua
local data = { name = 'test', age = 25, active = true }
local find_keys = { 'name', 'email', 'phone' }

print(table.has_any_key(data, find_keys))   -- true (chave 'name' está em find_keys)

local find_keys2 = { 'email', 'phone', 'address' }
print(table.has_any_key(data, find_keys2))  -- false

table.equals(table1, table2)

Compara recursivamente duas tabelas para igualdade completa.

lua
local table1 = { a = 1, b = { c = 2, d = 3 } }
local table2 = { a = 1, b = { c = 2, d = 3 } }
local table3 = { a = 1, b = { c = 2, d = 4 } }

print(table.equals(table1, table2))  -- true
print(table.equals(table1, table3))  -- false

table.is_empty(table)

Verifica se a tabela está vazia.

lua
print(table.is_empty({}))           -- true
print(table.is_empty({ a = 1 }))    -- false

table.is_position(table)

Verifica se a tabela representa coordenadas.

lua
print(table.is_position({ x = 10, y = 20, z = 30 }))  -- true
print(table.is_position({ x = 10, y = 20 }))          -- false
print(table.is_position({ a = 1, b = 2, c = 3 }))     -- false

table.each_value_is(table, value)

Verifica que todos os elementos da tabela são iguais ao valor especificado. Por padrão verifica para true.

lua
local data1 = { true, true, true }
print(table.each_value_is(data1))  -- true

local data2 = { 5, 5, 5, 5 }
print(table.each_value_is(data2, 5))  -- true

local data3 = { 1, 2, 3 }
print(table.each_value_is(data3, 1))  -- false

table.count(table)

Conta o número de elementos na tabela.

NOTE

Para tabelas com chaves inteiras, use #table.
Como o operador # não funciona em tabelas com chaves não-inteiras, use table.count para elas.

lua
local data = { a = 1, b = 2, c = 3 }
print(table.count(data))  -- 3
print(#data)              -- 0, porque o operador `#` não funciona com chaves não-inteiras.

local array = { 1, 2, 3, 4, 5 }
print(#array) -- 5

table.generate_sequence(max, start_from?, step?)

Gera uma sequência de números.

lua
local seq1 = table.generate_sequence(5)
print(dump(seq1))  -- { 1, 2, 3, 4, 5 }

local seq2 = table.generate_sequence(10, 2, 2)
print(dump(seq2))  -- { 2, 4, 6, 8, 10 }

local seq3 = table.generate_sequence(1, 5, -1)
print(dump(seq3))  -- { 5, 4, 3, 2, 1 }

table.only(table, only)

Retorna uma nova tabela contendo dados apenas com as chaves especificadas.

lua
local data = { name = 'Alek', age = 25, city = 'Vladivostok', country = 'Russia' }
local filtered = table.only(data, { 'name', 'age' })
-- `filtered` contém `{ name = 'Alek', age = 25 }`
print(filtered.name, filtered.age)    -- 'Alek', 25
print(filtered.city)                  -- nil

table.except(table, keys)

Retorna uma nova tabela contendo dados sem as chaves especificadas.
(copia a tabela, excluindo as chaves especificadas)

lua
local data = { name = 'Alek', age = 25, city = 'Vladivostok', country = 'Russia' }
local filtered = table.except(data, { 'age', 'country' })
-- `filtered` contém `{ name = 'Alek', city = 'Vladivostok' }`
print(filtered.name, filtered.city)      -- 'Alek', 'Vladivostok'
print(filtered.age,  filtered.country)   -- nil, nil

table.merge(table1, table2, overwrite?)

Mescla tabelas recursivamente.

Por padrão, a primeira tabela não é sobrescrita, uma nova é criada.

lua
local defaults = { theme = 'dark', font = { size = 12, family = 'Arial' } }
local user_config = { font = { size = 16 }, language = 'en' }

local merged = table.merge(defaults, user_config)
print(dump(merged))
-- {
--     theme = "dark",
--     font = {
--         size = 16,
--         family = "Arial",
--     },
--     language = "en",
-- }

Sobrescrever a primeira tabela:

lua
table.merge(defaults, user_config, true)

TIP

É melhor usar table.overwrite() para melhor legibilidade.

table.join(table1, table2, recursively?)

Adiciona chaves ausentes de table2 a table1.
Valores que são tabelas são copiados usando table.copy().

lua
local base     = { a = 1, b =  2        }
local addition = {        b = 10, c = 3 }

table.join(base, addition)
print(dump(base))  -- { a = 1, b = 2, c = 3 }

Se recursively for true, a função será aplicada recursivamente apenas para valores que são tabelas em ambos table1 e table2.

lua
local base     = { a = 1, b = { c = 2          } }
local addition = {        b = { c = 10, d = 20 } }

table.join(base, addition, true)
print(dump(base))
-- {
--     a = 1,
--     b = {
--         c = 2,
--         d = 20,
--     },
-- }

table.overwrite(table1, table2)

Sobrescreve completamente table1 com valores de table2.

Variante semântica para table.merge(table1, table2, true).

table.merge_values(table1, table2)

Mescla valores de duas tabelas em uma, removendo duplicatas.
Ordem é preservada - primeiro valores de table1, depois de table2 que não estavam em table1.

lua
local table1 = { 'apple', 'banana', 'cherry' }
local table2 = { 'banana', 'date', 'apple', 'elderberry' }

local merged = table.merge_values(table1, table2)
print(dump(merged))  -- { 'apple', 'banana', 'cherry', 'date', 'elderberry' }

table.map(table, callback, overwrite?)

Aplica função a cada elemento da tabela.
callback: fun(value: any, key: any): any - aceita valor e chave, retorna novo valor.

Por padrão retorna uma nova tabela.

lua
local numbers = { 1, 2, 3, 4, 5 }
local squared = table.map(numbers, function(x) return x * x end)
print(dump(squared))
-- { 1, 4, 9, 16, 25 }

local data = { a = 10, b = 20 }
local doubled = table.map(data, function(value, key)
	print(key, value)
	return value * 2
end)
-- a       10
-- b       20
print(dump(doubled))
-- { a = 20, b = 40 }

Se overwrite for true, então a função modifica a tabela original.

lua
local data = { a = 10, b = 20 }
table.map(data, function(value, key) return value * 2 end, true)
print(dump(data))  -- { a = 20, b = 40 }

table .walk/.each(table, callback)

Itera sobre a tabela aplicando função (não modifica a tabela).
callback: fun(value: any, key: any): void - aceita valor e chave; não retorna nada.

lua
local data = { a = 10, b = 20, c = 30 }
table.walk(data, function(value, key)
    print(key, value)
end)
-- a       10
-- c       30
-- b       20

Nome alternativo: table.each()

lua
local data = { a = 10, b = 20, c = 30 }
table.each(data, function(value, key)
    data[key] = value * 2
    -- Nada impede o acesso à upvalue `data`. Agora `data` foi sobrescrito.
end)
print(dump(data))  -- { a = 20, b = 40, c = 60 }

table.multiply_each_value(table, multiplier_table)

Multiplica cada valor da tabela pelo valor correspondente de multiplier_table por chave.

lua
local data = { a = 10, b = 20, c = 30 }
local multipliers = { a = 2, b = 0.5, c = 3 }

local result = table.multiply_each_value(data, multipliers)
print(dump(result))  -- { a = 20, b = 10, c = 90 }
-- Chaves sem multiplicador permanecem inalteradas

table.add_values(table1, table2, empty_value?, overwrite?)

Adiciona valores com as mesmas chaves de duas tabelas.

lua
local table1 = { a = 10, b = 20 }
local table2 = { b = 5, c = 15 }

local result = table.add_values(table1, table2)
print(dump(result))  -- { a = 10, b = 25, c = 15 }

-- Com valor vazio para chaves ausentes
local result2 = table.add_values(table1, table2, 0)
print(dump(result2))  -- { a = 10, b = 25, c = 15 }

table.sub_values(table1, table2, empty_value?, overwrite?)

Subtrai valores table2 de table1 para chaves iguais.

lua
local table1 = { a = 10, b = 20, c = 30 }
local table2 = { b = 5, c = 10, d = 5 }

local result = table.sub_values(table1, table2)
print(dump(result))  -- { a = 10, b = 15, c = 20, d = -5 }

table.mul_values(table1, table2, empty_value?, overwrite?)

Multiplica valores com as mesmas chaves de duas tabelas.

lua
local table1 = { a = 2, b = 3 }
local table2 = { b = 4, c = 5 }

local result = table.mul_values(table1, table2)
print(dump(result))  -- { a = 2, b = 12, c = 5 }

table.div_values(table1, table2, empty_value?, overwrite?)

Divide valores table1 pelos valores table2 para chaves iguais.

lua
local table1 = { a = 10, b = 20, c = 30 }
local table2 = { b = 5, c = 10, d = 2 }

local result = table.div_values(table1, table2)
print(dump(result))  -- { a = 10, b = 4, c = 3, d = 0.5 }

Math

math .limit/.clamp(value, min, max)

Limita valor ao intervalo especificado.
Nome alternativo: math.clamp().

lua
local health = 150
local max_health = 100
local clamped_health = math.limit(health, 0, max_health)
print(clamped_health)  -- 100

math.is_within(value, min, max)

Verifica que o valor está estritamente dentro do intervalo (min < value < max).

lua
print(math.is_within(5, 1, 10))   -- true
print(math.is_within(1, 1, 10))   -- false (limites não incluídos)
print(math.is_within(10, 1, 10))  -- false

math.is_among(value, min, max)

Verifica que o valor está dentro do intervalo, incluindo limites (min <= value <= max).

lua
print(math.is_among(5, 1, 10))   -- true
print(math.is_among(1, 1, 10))   -- true
print(math.is_among(10, 1, 10))  -- true

math.is_in_range(value, min, max)

Verifica que o valor está dentro do intervalo semiaberto (min, max] (min < value <= max).

lua
print(math.is_in_range(5, 1, 10))   -- true
print(math.is_in_range(1, 1, 10))   -- false (igual ao mínimo)
print(math.is_in_range(10, 1, 10))  -- true (igual ao máximo)

math.is_near(value, near, gap?)

Verifica que o valor está próximo do especificado (|value - near| <= gap).

lua
print(math.is_near(10, 12))        -- false (gap = 1 por padrão)
print(math.is_near(11, 12))        -- true
print(math.is_near(10, 12, 3))     -- true (gap = 3)

math.quadratic_equation_roots(a, b, c)

Resolve equação quadrática da forma y = a*x^2 + b*x + c.

lua
local root1, root2 = math.quadratic_equation_roots(1, -5, 6)
print(root1, root2)  -- 3, 2

-- Sem raízes reais
local r1, r2 = math.quadratic_equation_roots(1, 0, 1)
print(r1, r2)  -- nil, nil

math.point_on_circle(radius, angle)

Calcula um ponto em um círculo.

lua
local x, z = math.point_on_circle(5, math.pi/4)
print(x, z)  -- coordenadas de um ponto em um círculo com raio 5 no ângulo 45°

Debug

__FILE__(depth?, full?)

Retorna o nome do arquivo atual ou do arquivo da função chamadora dependendo da profundidade da pilha.

  • depth? - profundidade da pilha de chamadas (padrão 0)
  • full? - mostrar caminho completo (padrão false)
lua
-- Obter caminho relativo do arquivo
print(__FILE__())  -- 'mods/Voxrame/helpers/src/lua_ext/debug.lua'

-- Obter caminho completo do arquivo
print(__FILE__(0, true))  -- '/home/alek13/projects/my-game/mods/Voxrame/helpers/src/lua_ext/debug.lua'

-- Obter arquivo 2 níveis acima na pilha de chamadas
print(__FILE__(2))  -- arquivo da função que chamou a função chamadora

__LINE__(depth?)

Retorna o número da linha atual ou da linha da função chamadora dependendo da profundidade da pilha.

lua
print(__LINE__())  -- 57

-- Obter número da linha da função chamadora
print(__LINE__(1))  -- número da linha no arquivo de chamada

__FILE_LINE__(depth?, full?)

Retorna arquivo e linha no formato "caminho/relativo/para/arquivo:linha".

lua
print(__FILE_LINE__())  -- 'mods/Voxrame/helpers/src/lua_ext/debug.lua:65'

-- Com caminho completo
print(__FILE_LINE__(0, true))  -- '/home/alek13/projects/my-game/mods/Voxrame/helpers/src/lua_ext/debug.lua:65'

__DIR__(depth?)

Retorna o diretório do arquivo atual ou do arquivo da função chamadora dependendo da profundidade da pilha.

lua
print(__DIR__())  -- 'mods/Voxrame/helpers/src/lua_ext/'

__FUNC__(depth?)

Retorna o nome da função atual.

lua
function my_function()
    print(__FUNC__())  -- 'my_function'
end

Produz o conteúdo de todos os parâmetros passados ....
Antes da saída, adiciona nome do arquivo e linha @ <file>:<line>.

Se with_trace for true, adicionalmente produz stack trace.

NOTE

Se seu terminal suporta links, cada @ <file>:<line> será vinculado à abertura da IDE, veja readme.md para configuração.

TIP

Use pd() e pdt() para sintaxe mais concisa. Veja exemplos abaixo.

pd(...)

Abreviação para print_dump. Chama print_dump com with_trace == false.

lua
local player_name = 'test_player'
local position = { x = 10, y = 20, z = 30 }

pd(player_name, position)

output:

[93m@ [0m[33mmods/lord/Core/map/src/map/Corridor.lua[0m[97m:[0m[32m14[0m
[36mplayer_name:[0m "test_player"
[36m   position:[0m {
    x = 10,
    y = 20,
    z = 30,
}

pdt(...)

Abreviação para print_dump traced. Chama print_dump com with_trace == true.

lua
local player_name = 'test_player'
local position = { x = 10, y = 20, z = 30 }

pdt(player_name, position)

output:

[93m@ [0m[33mmods/lord/Core/map/src/map/Corridor.lua[0m[97m:[0m[32m14[0m
[3m[2m   1   [0m[93m@[0m [C][36m: in dofile[0m
[3m[2m   2   [0m[93m@ [0m[33mmods/lord/Core/builtin_ext/src/mod/require.lua[0m[97m:[0m[32m29[0m[36m: in require[0m
[3m[2m   3   [0m[93m@ [0m[33mmods/lord/Core/map/src/map.lua[0m[97m:[0m[32m9[0m[36m: in main[0m
[3m[2m   4   [0m[93m@ [0m [C][36m: in dofile[0m
[3m[2m   5   [0m[93m@ [0m[33mmods/lord/Core/builtin_ext/src/mod/require.lua[0m[97m:[0m[32m29[0m[36m: in require[0m
[3m[2m   6   [0m[93m@ [0m[33mmods/lord/Core/map/init.lua[0m[97m:[0m[32m4[0m[36m: in mod_init_function[0m
[3m[2m   7   [0m[93m@ [0m[33mmods/lord/Core/builtin_ext/src/mod.lua[0m[97m:[0m[32m80[0m[36m: in mod[0m
[3m[2m   8   [0m[93m@ [0m[33mmods/lord/Core/map/init.lua[0m[97m:[0m[32m3[0m[36m: in main[0m
[36mplayer_name:[0m "test_player"
[36m   position:[0m {
    x = 10,
    y = 20,
    z = 30,
}

debug.measure(name, callback, print_result?)

Mede o tempo de execução da função.

lua
local function heavy_calculation()
    local sum = 0
    for i = 1, 2000000 do
        sum = sum + math.random(1, 100) + math.sin(i)
    end
end

-- Medir com saída de resultado
debug.measure('calculation', heavy_calculation, true)
debug.measure('calculation', heavy_calculation, true)
debug.measure('calculation', heavy_calculation, true)
debug.measure('calculation', heavy_calculation, true)
debug.measure('calculation', heavy_calculation, true)
-- output:
-- Measure of [calculation]:  Time:    42 ms ;  Average:    42 ms
-- Measure of [calculation]:  Time:    58 ms ;  Average:    50 ms
-- Measure of [calculation]:  Time:    58 ms ;  Average:    53 ms
-- Measure of [calculation]:  Time:    35 ms ;  Average:    48 ms
-- Measure of [calculation]:  Time:    33 ms ;  Average:    45 ms


-- Medir sem saída
local time, avg, count = debug.measure('calculation', heavy_calculation)
print(time, avg, count)
local time, avg, count = debug.measure('calculation', heavy_calculation)
print(time, avg, count)
-- output:
-- 33.075  43.170833333333 6
-- 33.135  41.737142857143 7

debug.mesure_print(name)

Produz estatísticas de medições anteriores name obtidas por chamadas a debug.measure(name, ....).

lua
debug.mesure_print('calculation')
-- output:
-- Measure of [calculation]: Average time:    42 ms ; Last time:    33 ms ; Count of mesures:     7

Global

errorf(message, ...)

Similar ao error() em Lua, mas message pode ser um string template com parâmetros especificados, similar ao string.format().

lua
local player_name = nil
errorf('Jogador '%s' não encontrado', player_name)
-- Erro: Jogador 'nil' não encontrado

output (quando debug está habilitado):

[93m@ [0m[33mmods/lord/Core/map/src/map/Corridor.lua[0m[97m:[0m[32m9[0m
[32m++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++[0m
[1m[91mERROR:[0m
[91m  Jogador `nil` não encontrado[0m

[1m[91mStack trace:[0m
[3m[2m   1   [0m[93m@[0m [C][36m: in error[0m
[3m[2m   2   [0m[93m@ [0m[33mmods/lord/Core/helpers/src/lua_ext/global.lua[0m[97m:[0m[32m9[0m[36m: in errorf[0m
[3m[2m   3   [0m[93m@ [0m[33mmods/lord/Core/map/src/map/Corridor.lua[0m[97m:[0m[32m12[0m[36m: in main[0m
[3m[2m   4   [0m[93m@ [0m [C][36m: in dofile[0m
[3m[2m   5   [0m[93m@ [0m[33mmods/lord/Core/builtin_ext/src/mod/require.lua[0m[97m:[0m[32m29[0m[36m: in require[0m
[3m[2m   6   [0m[93m@ [0m[33mmods/lord/Core/map/src/map.lua[0m[97m:[0m[32m9[0m[36m: in main[0m
[3m[2m   7   [0m[93m@ [0m [C][36m: in dofile[0m
[3m[2m   8   [0m[93m@ [0m[33mmods/lord/Core/builtin_ext/src/mod/require.lua[0m[97m:[0m[32m29[0m[36m: in require[0m
[3m[2m   9   [0m[93m@ [0m[33mmods/lord/Core/map/init.lua[0m[97m:[0m[32m4[0m[36m: in mod_init_function[0m
[3m[2m  10   [0m[93m@ [0m[33mmods/lord/Core/builtin_ext/src/mod.lua[0m[97m:[0m[32m80[0m[36m: in mod[0m
[3m[2m  11   [0m[93m@ [0m[33mmods/lord/Core/map/init.lua[0m[97m:[0m[32m3[0m[36m: in main[0m

[32m++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++[0m
Tratamento de erros no Luanti

WARNING

O stack trace conterá linhas extras, porque Luanti não passa o level especificado para core.error_handler().

errorlf(message, level, ...)

Como em errorf() você pode passar um string de formato e parâmetros, e também especificar o nível de trace.

lua
errorlf('Erro nos dados', 3, 'valor: %d', 42)
-- Erro com trace 3 níveis acima

veja tratamento de erros no Luanti

assertf(condition, message, ...)

Similar ao assert() em Lua, mas como message você pode especificar um string de formato com parâmetros, similar ao string.format().

Chama errorf() se a condição condition não for atendida.

lua
-- Continua execução se player existe, senão erro
local player = nil
assertf(player, 'Jogador `%s` não encontrado', player)

IO

io.file_exists(name)

Verifica se um arquivo existe.

lua
if io.file_exists('config.txt') then
    print('Arquivo de configuração encontrado')
else
    print('Arquivo de configuração ausente')
end

io.dirname(path)

Retorna o diretório do caminho.

lua
print(io.dirname('/home/user/project/file.txt'))  -- '/home/user/project'
print(io.dirname('relative/path/file.txt'))       -- 'relative/path'
print(io.dirname('file.txt'))                     -- '.'

io.write_to_file(filepath, content, mode?)

Escreve conteúdo em um arquivo.

lua
local success, error_code, error_message = io.write_to_file('data.txt', 'Hello, World!')

if success then
    print('Dados gravados com sucesso')
else
    print('Erro de gravação:', error_code, error_message)
end

-- Anexar ao final do arquivo
io.write_to_file('log.txt', 'Nova entrada\n', 'a')

io.read_from_file(filepath, mode?)

Lê todo o conteúdo de um arquivo.
Retorna string com conteúdo do arquivo em caso de sucesso ou false, error_code, error_message em caso de erro.

lua
local content = io.read_from_file('config.json')
if content then
    print('Conteúdo do arquivo:', content)
else
    print('Erro de leitura do arquivo')
end

Tratamento de erros

lua
local success, error_code, error_message = io.read_from_file('nonexistent.txt')
if not success then
    print('Erro:', error_code, error_message)
end
-- Erro: 2       nonexistent.txt: No such file or directory

ou:

lua
local success = io.read_from_file('nonexistent.txt')
if not success then
    local error_code, error_message = io.get_file_error()
    print('Erro:', error_code, error_message)
end
-- Erro: 2       nonexistent.txt: No such file or directory

Leitura em modo binário

lua
local binary_content = io.read_from_file('image.png', 'rb')
if binary_content then
    print('Tamanho do arquivo:', #binary_content, 'bytes')
end

io.get_file_error()

Retorna o código e mensagem do último erro das funções io.read_from_file() ou io.write_to_file().

lua
local success = io.read_from_file('nonexistent.txt')
if not success then
    local error_code, error_message = io.get_file_error()
    print('Erro:', error_code, error_message)
end
-- Output: Erro: 2       nonexistent.txt: No such file or directory
lua
local success = io.write_to_file('/readonly/file.txt', 'data')
if not success then
    local error_code, error_message = io.get_file_error()
    print('Erro de gravação:', error_code, error_message)
end
-- Output: Erro de gravação: 13       /readonly/file.txt: Permission denied

OS

os.DIRECTORY_SEPARATOR

Separador de diretório para o sistema operacional atual.

lua
local DS = os.DIRECTORY_SEPARATOR

print(DS)  -- '/' no Linux/Mac, '\' no Windows
print('folder' .. DS .. 'file.txt')
-- no Linux/Mac: 'folder/file.txt'
-- no Windows:   'folder\file.txt'