Pular para o conteúdo principal

Lua Scripting: Primeiros passos

Esta página ensina a escrever o seu primeiro script Lua para um prop do FreeMinecraftModels, desde um ficheiro vazio até um prop interativo funcional. No final, vai compreender hooks, context, a Prop API e a estrutura geral de cada ficheiro de script de prop.

Assim que estiver confortável com o básico, continue com as páginas complementares:

Funcionalidade experimental

Os scripts Lua de props são atualmente experimentais. Os nomes dos hooks, métodos auxiliares e comportamento ainda podem mudar à medida que o FreeMinecraftModels evolui, por isso teste cuidadosamente antes de os usar num servidor de produção.

Relação com o EliteMobs Lua

O FreeMinecraftModels partilha o mesmo motor Lua (Magmacore) que o EliteMobs. Se já escreve poderes Lua para o EliteMobs, os conceitos fundamentais -- hooks, context, api_version, scheduler, zonas e a sandbox -- são idênticos. A diferença é:

  • Os scripts do EliteMobs executam em bosses e têm hooks como on_boss_damaged_by_player, on_enter_combat, etc.
  • Os scripts do FMM executam em props e têm hooks como on_right_click, on_left_click, on_projectile_hit, etc.

As APIs context.world, context.zones, context.scheduler, context.state e context.log são as mesmas em ambos os plugins. Esta página cobre apenas o que é específico para props do FMM.


O que são scripts de props

Scripts de props são ficheiros .lua independentes que se encontram na pasta plugins/FreeMinecraftModels/scripts/. São referenciados a partir de um ficheiro de config YAML que fica ao lado do ficheiro de modelo, e executam sempre que o prop é gerado no mundo.

Para que são bons os scripts de props

Os scripts de props destacam-se quando precisa de:

  • Props interativos que respondem a cliques dos jogadores (portas, alavancas, botões)
  • Props decorativos invulneráveis que não podem ser destruídos pelos jogadores
  • Gatilhos de proximidade que detetam quando jogadores entram ou saem de uma área
  • Props animados que reproduzem animações na interação ou com um temporizador
  • Props emissores de som que reproduzem sons quando clicados ou quando alguém se aproxima
  • Qualquer comportamento de prop que exija lógica além da decoração estática

Se o seu prop é puramente decorativo e não precisa de interação, não precisa de um script.


Para quem é esta página

Esta página foi escrita para três tipos de leitores:

  • Alguém que já conhece o scripting Lua do EliteMobs e quer aprender os hooks e APIs específicos do FMM
  • Alguém que é novo no scripting Lua e precisa de uma referência completa com nomes exatos para props
  • Alguém que usa IA para redigir scripts de props e precisa de detalhe suficiente para saber quando a IA inventou algo falso

Não precisa de se tornar um programador Lua completo antes de escrever scripts de props úteis. Para a maioria dos scripts de props práticos, as únicas coisas que realmente precisa são:

  • Como colocar um hook válido na tabela retornada
  • Como ler valores do context
  • Como parar cedo com if ... then return end
  • Como chamar alguns métodos auxiliares exatamente

Mini-introdução ao Lua

Se é completamente novo no Lua, aqui está a sintaxe mínima de que precisa.

Variáveis

Use local para armazenar um valor:

local animation_name = "open"
local sound_volume = 1.0

Funções

Funções são blocos de lógica reutilizáveis:

local function log_click(context)
context.log:info("Prop was clicked!")
end

Verificações if

Use if quando algo só deve acontecer por vezes:

if context.event == nil then
return
end

nil

nil significa "sem valor". Vai verificá-lo frequentemente:

if context.event ~= nil then
context.event.cancel()
end

Tabelas

O Lua usa tabelas para objetos com chaves nomeadas e para a definição do script retornado:

return {
api_version = 1,

on_spawn = function(context)
end
}

Comentários

Use -- para notas:

-- Cancel the damage event so the prop cannot be broken
context.event.cancel()
dica

Para uma introdução mais completa ao Lua, consulte a página Primeiros passos com EliteMobs. Os fundamentos de sintaxe são idênticos.


Onde ficam os ficheiros

Ficheiros de script

Coloque os ficheiros .lua na pasta central de scripts:

plugins/
FreeMinecraftModels/
scripts/
invulnerable.lua
interactive_door.lua
proximity_sound.lua

O FMM descobre todos os ficheiros .lua em plugins/FreeMinecraftModels/scripts/ ao iniciar.

Ficheiros de modelo e ficheiros de config

Cada ficheiro de modelo pode ter um ficheiro .yml de config associado no mesmo diretório:

plugins/
FreeMinecraftModels/
models/
torch_01.fmmodel
torch_01.yml <-- config de script para torch_01
scripts/
invulnerable.lua <-- referenciado por torch_01.yml

O ficheiro .yml de config é o que liga um modelo aos seus scripts.


Formato do ficheiro de config

O ficheiro de config YAML que fica ao lado de um ficheiro de modelo tem dois campos:

isEnabled: true
scripts:
- invulnerable.lua
CampoTipoPredefinidoNotas
isEnabledbooleantrueSe os scripts estão ativos para este prop
scriptslista de strings[]Nomes de ficheiros .lua na pasta scripts/

Pode anexar múltiplos scripts ao mesmo prop. Cada script é a sua própria instância independente.

Geração diferida de config

Quando um prop é gerado e não existe um ficheiro .yml associado, o FMM cria automaticamente um ficheiro de config predefinido com isEnabled: true e uma lista scripts: vazia. Isto acontece de forma assíncrona, portanto o prop não terá scripts na sua primeira geração -- só depois de a config ser criada e de a editar para adicionar nomes de ficheiros de script.

Isto significa:

  1. Coloque o seu ficheiro de modelo em models/
  2. Gere o prop uma vez (o FMM cria o .yml automaticamente)
  3. Edite o .yml gerado para adicionar os seus nomes de ficheiros de script
  4. Regere o prop ou recarregue o servidor (os scripts estão agora ativos)

Referência de hooks

Cada ficheiro de script Lua de prop retorna uma tabela. Cada chave nessa tabela (além de api_version e priority) deve ser um dos hooks listados abaixo. O runtime chama a função correspondente sempre que o evento de jogo associado é disparado.

HookDispara quandoNotas
on_spawnO prop é gerado no mundoExecuta uma vez quando o script é vinculado
on_game_tickUma vez por tick do servidor (50 ms)Só ativo se o script definir este hook
on_destroyO prop é removido do mundoHook de limpeza
on_left_clickUm jogador clica com o botão esquerdo (ataca) o propcontext.event é o evento de dano
on_right_clickUm jogador clica com o botão direito no propcontext.event é o evento de interação
on_projectile_hitUm projétil atinge o propcontext.event é o evento de impacto de projétil
on_zone_enterUm jogador entra numa zona vigiadaRequer que uma vigilância de zona esteja configurada
on_zone_leaveUm jogador sai de uma zona vigiadaRequer que uma vigilância de zona esteja configurada

Contrato mínimo do ficheiro

Cada script Lua de prop deve fazer return de uma tabela.

Campos de nível superior obrigatórios e opcionais

CampoObrigatórioTipoNotas
api_versionSimNumberAtualmente deve ser 1
priorityNãoNumberPrioridade de execução. Valores mais baixos executam primeiro. Predefinido 0
Chaves de hook suportadasNãoFunctionDeve usar um dos nomes exatos de hook listados na Referência de hooks

Regras de validação

  • O ficheiro deve retornar uma tabela.
  • api_version é obrigatório e atualmente deve ser 1.
  • priority deve ser numérico se presente.
  • Cada chave de nível superior adicional deve ser um nome de hook suportado.
  • Cada chave de hook deve apontar para uma função.
  • Chaves de nível superior desconhecidas são rejeitadas.

Funções auxiliares e constantes locais devem ficar acima do return final, não dentro da tabela retornada.


O seu primeiro script de prop funcional, construído passo a passo

Antes do passo 1: Configurar a config

  1. Coloque o seu ficheiro de modelo (ex.: my_prop.fmmodel) em plugins/FreeMinecraftModels/models/
  2. Gere o prop uma vez para criar a config .yml
  3. Crie o seu ficheiro de script em plugins/FreeMinecraftModels/scripts/first_test.lua
  4. Edite plugins/FreeMinecraftModels/models/my_prop.yml:
isEnabled: true
scripts:
- first_test.lua
  1. Regere o prop ou recarregue o servidor

Passo 1: Fazer o ficheiro carregar

return {
api_version = 1,

on_spawn = function(context)
end
}

Se isto carregar sem erros na consola, provou:

  • O ficheiro é Lua válido
  • O FMM encontrou-o na pasta scripts/
  • A config referencia-o corretamente
  • A forma da tabela retornada está correta

Passo 2: Fazer o prop fazer algo visível

return {
api_version = 1,

on_spawn = function(context)
context.log:info("Prop script loaded for: " .. (context.prop.model_id or "unknown"))
end
}

Verifique a consola do servidor. Se vir a mensagem de log, o seu hook está a disparar.

Passo 3: Reagir a um clique do jogador

return {
api_version = 1,

on_right_click = function(context)
context.log:info("Prop was right-clicked!")
end
}

Clique com o botão direito no prop no jogo. Se a consola mostrar a mensagem, o hook de clique está a funcionar.

Passo 4: Cancelar dano para tornar o prop invulnerável

return {
api_version = 1,

on_left_click = function(context)
if context.event then
context.event.cancel()
end
end
}

Este é o padrão usado pelo script predefinido invulnerable.lua. Cancela o evento de dano para que o armor stand que suporta o prop não possa ser destruído.

Passo 5: Reproduzir uma animação ao clicar

return {
api_version = 1,

on_right_click = function(context)
context.prop:play_animation("open", true, false)
end
}

Isto reproduz a animação "open" no modelo do prop, com mistura e sem loop.


O que é context?

Cada função de hook recebe um argumento chamado context. Pense nele como uma caixa de ferramentas que o FMM lhe entrega cada vez que algo acontece -- contém tudo o que precisa para interagir com o prop, o mundo, zonas e mais.

on_right_click = function(context)
-- context.prop = o prop que foi clicado
-- context.event = o evento de clique (pode ser cancelado)
-- context.world = ferramentas para partículas, sons, consultas de blocos
-- context.state = o seu próprio armazenamento persistente
-- context.log = registo na consola
-- context.scheduler = tarefas diferidas e repetitivas
-- context.zones = criação e vigilância de zonas espaciais
end

Não cria context -- o FMM cria-o e passa-o ao seu hook.

info

context é criado de novo para cada chamada de hook, exceto context.state que persiste durante toda a vida do prop. Isto significa que pode armazenar dados em context.state e lê-los mais tarde num hook diferente.


APIs chave de context

Aqui está um resumo do que está disponível. Para detalhes completos, consulte Prop API.

  • context.prop -- A entidade do prop. Fornece model_id, current_location, play_animation() e stop_animation().

  • context.event -- O evento Bukkit que acionou este hook. Disponível em on_left_click, on_right_click e on_projectile_hit. Fornece cancel(), uncancel() e is_cancelled. É nil em hooks sem evento (como on_spawn e on_game_tick).

  • context.state -- Uma tabela Lua simples que persiste durante a vida do prop. Use-a para armazenar flags, estados de alternância, IDs de tarefas e qualquer coisa que precise de lembrar entre hooks.

  • context.log -- Registo na consola com log:info(msg), log:warn(msg) e log:error(msg).

  • context.scheduler -- Tarefas diferidas e repetitivas com scheduler:run_later(ticks, callback) e scheduler:run_repeating(delay, interval, callback). Os callbacks recebem um context novo. Cancele tarefas com scheduler:cancel(taskId).

  • context.world -- Interação com o mundo: partículas, sons, consultas de blocos, relâmpagos, entidades próximas. Consulte Prop API para a lista completa de métodos.

  • context.zones -- Criação e vigilância de zonas espaciais (esferas, cilindros, cuboides). Consulte Prop API para a lista completa de métodos.


Sintaxe de métodos: : vs .

Em Lua, object:method(arg) é uma abreviação de object.method(object, arg). A API do FMM aceita ambas as formas:

context.log:info("hello")
context.log.info("hello") -- a mesma coisa

Toda a documentação usa : de forma consistente.


Modelos prontos para copiar e colar

Menor script de prop válido

return {
api_version = 1,

on_spawn = function(context)
end
}

Modelo de prop invulnerável

return {
api_version = 1,

on_left_click = function(context)
if context.event then
context.event.cancel()
end
end
}

Modelo de prop interativo

return {
api_version = 1,

on_spawn = function(context)
context.state.is_active = false
end,

on_right_click = function(context)
context.state.is_active = not context.state.is_active

if context.state.is_active then
context.prop:play_animation("activate", true, true)
else
context.prop:stop_animation()
end
end
}

Layout de ficheiro maior

local ANIMATION_NAME = "idle"

local function do_something(context)
context.log:info("Doing something!")
end

return {
api_version = 1,
priority = 0,

on_spawn = function(context)
context.state.task_id = nil
end,

on_right_click = function(context)
do_something(context)
end,

on_destroy = function(context)
if context.state.task_id ~= nil then
context.scheduler:cancel(context.state.task_id)
end
end
}

Primeiro fluxo de trabalho real

Ao construir um script de prop completamente novo, use esta ordem:

  1. Crie o ficheiro .lua e faça on_spawn funcionar.
  2. Adicione o nome do ficheiro de script à config .yml do prop.
  3. Mude para o hook que realmente quer (ex.: on_right_click).
  4. Adicione primeiro uma mensagem de log, antes de animações ou efeitos.
  5. Adicione um efeito real (animação, som, partícula).
  6. Só depois disso, adicione funções auxiliares, state, lógica de scheduler ou zonas.

Essa ordem torna a depuração dramaticamente mais fácil porque só uma coisa muda de cada vez.


Scripts predefinidos

O FMM vem com um script Lua predefinido:

  • invulnerable.lua -- Cancela eventos de dano por clique esquerdo, tornando o prop indestrutível. Este é o script de prop útil mais simples.

Pode encontrar mais exemplos na página Exemplos e padrões.


Lua Sandbox

Os scripts de props executam dentro do mesmo ambiente LuaJ sandboxed que o EliteMobs. As restrições da sandbox são idênticas. Para a lista completa de globais removidos e funções da biblioteca padrão disponíveis, consulte a página EliteMobs Hooks & Lifecycle.

Em resumo:

  • Removidos: debug, dofile, io, load, loadfile, luajava, module, os, package, require
  • Disponíveis: Todas as funções math.*, string.*, table.*, pairs, ipairs, type, tostring, tonumber, pcall, print e mais
dica

print escreve na consola do servidor, mas prefira context.log:info(msg) para output. As mensagens de log são prefixadas com o nome do ficheiro de script, facilitando o rastreio de qual script produziu a mensagem.


Próximos passos

  • Prop API -- referência completa de context.prop, context.event, context.world, context.zones e context.scheduler
  • Exemplos e padrões -- scripts completos e funcionais com explicações
  • Resolução de problemas -- problemas comuns, dicas de depuração e uma checklist de QC

Se também escreve poderes Lua para o EliteMobs, as APIs partilhadas (context.world, context.zones, context.scheduler, context.state, context.log) funcionam de forma idêntica. Consulte a documentação Lua do EliteMobs para as APIs específicas de bosses.