Scripting Lua: Primeiros Passos
Esta página ensina você a escrever seu primeiro script Lua para um prop do FreeMinecraftModels, de um arquivo vazio até um prop interativo funcional. Ao final, você entenderá hooks, context, a API de props e a forma geral de cada arquivo de script de prop.
Quando estiver confortável com o básico, continue com as páginas complementares:
- API de Props -- as APIs
context.prop,context.event,context.worlde outros contexts - Exemplos e Padrões -- scripts completos e funcionais que você pode estudar e adaptar
- Solução de Problemas -- erros comuns, dicas de depuração e checklist de QC
Scripts Lua para props são atualmente experimentais. Nomes de hooks, métodos auxiliares e comportamentos ainda podem mudar conforme o FreeMinecraftModels evolui, então teste cuidadosamente antes de usá-los em um servidor de produção.
FreeMinecraftModels compartilha o mesmo motor Lua (Magmacore) que o EliteMobs. Se você já escreve poderes Lua para EliteMobs, os conceitos centrais -- hooks, context, api_version, scheduler, zones e o sandbox -- são idênticos. A diferença é:
- Scripts EliteMobs rodam em bosses e têm hooks como
on_boss_damaged_by_player,on_enter_combat, etc. - Scripts FMM rodam 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 arquivos .lua independentes que ficam na pasta plugins/FreeMinecraftModels/scripts/. Eles são referenciados a partir de um arquivo de configuração YAML que fica ao lado do arquivo de modelo, e rodam sempre que o prop é spawnado no mundo.
Para Que Scripts de Props São Bons
Scripts de props brilham quando você precisa de:
- Props interativos que respondem a cliques de jogadores (portas, alavancas, botões)
- Props decorativos invulneráveis que não podem ser quebrados por jogadores
- Gatilhos de proximidade que detectam quando jogadores entram ou saem de uma área
- Props animados que reproduzem animações por interação ou por timer
- Props emissores de som que tocam sons quando clicados ou quando alguém se aproxima
- Qualquer comportamento de prop que requer lógica além de decoração estática
Se seu prop é puramente decorativo e não precisa de interação, você não precisa de um script.
O Que São Scripts de Item
Scripts de item usam o mesmo formato de arquivo .lua e a mesma pasta scripts/ que scripts de prop. A diferença é que são vinculados a itens customizados -- modelos que têm um campo material: definido no seu arquivo de configuração YML. Enquanto scripts de prop rodam quando uma entidade prop é spawnada no mundo, scripts de item rodam quando um jogador equipa o item customizado (mão principal, mão secundária ou slot de armadura) e param quando o item é desequipado.
Como Scripts de Item Funcionam
- Ativação: Uma instância de script é criada quando um jogador equipa um item customizado do FMM. Scripts são por-jogador por-tipo-de-item -- uma
ScriptInstancepor par (jogador, itemId). - Desativação: A instância de script é destruída quando o item é desequipado (movido para fora do slot ativo, dropado, ou o jogador desconecta).
- Identificação de itens: Itens customizados são identificados pela chave PDC (PersistentDataContainer)
fmm_item_id, que é diferente domodel_iddo prop. Para obter um item com as tags corretas, use/fmm giveitem <id>ou o menu de admin. - Contexto: Hooks de item recebem
contextcomcontext.player,context.item,context.world,context.state,context.scheduler,context.log, e (onde aplicável)context.event.
Para Que Scripts de Item São Bons
Scripts de item brilham quando você precisa de:
- Armas customizadas com habilidades especiais (espadas de gelo, varinhas mágicas)
- Ferramentas com ações únicas de clique direito ou shift+clique
- Itens consumíveis com efeitos customizados
- Armaduras com efeitos passivos enquanto usadas
- Itens que rastreiam uso ou têm durabilidade limitada
- Qualquer comportamento de item segurado além das mecânicas vanilla
Para Quem Esta Página É
Esta página é escrita para três tipos de leitores:
- Alguém que já conhece scripting Lua do EliteMobs e quer aprender os hooks e APIs específicos do FMM
- Alguém que é novo em scripting Lua e precisa de uma referência completa com nomes exatos para props
- Alguém usando IA para redigir scripts de props e precisando de detalhes suficientes para saber quando a IA inventou algo falso
Você não precisa se tornar um desenvolvedor Lua completo antes de escrever scripts úteis para props. Para a maioria dos scripts práticos de props, as únicas coisas que você realmente precisa são:
- Como colocar um hook válido na tabela retornada
- Como ler valores de
context - Como parar antecipadamente com
if ... then return end - Como chamar alguns métodos auxiliares exatamente
Mini Primer de Lua
Se você é completamente novo em Lua, aqui está a sintaxe mínima que você 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 reutilizáveis de lógica:
local function log_click(context)
context.log:info("Prop foi clicado!")
end
Verificações if
Use if quando algo deve acontecer apenas às vezes:
if context.event == nil then
return
end
nil
nil significa "sem valor". Você frequentemente verificará por ele:
if context.event ~= nil then
context.event.cancel()
end
Tabelas
Lua usa tabelas para objetos com chaves nomeadas e para a definição de script retornada:
return {
api_version = 1,
on_spawn = function(context)
end
}
Comentários
Use -- para notas:
-- Cancela o evento de dano para que o prop não possa ser quebrado
context.event.cancel()
Para um primer de Lua mais completo, veja a página Primeiros Passos do EliteMobs. O básico da sintaxe é idêntico.
Onde os Arquivos Ficam
Arquivos de Script
Coloque arquivos .lua na pasta central de scripts:
plugins/
FreeMinecraftModels/
scripts/
invulnerable.lua
interactive_door.lua
proximity_sound.lua
O FMM descobre todos os arquivos .lua em plugins/FreeMinecraftModels/scripts/ na inicialização.
Arquivos de Modelo e Arquivos de Configuração
Cada arquivo de modelo pode ter um arquivo de configuração .yml irmão no mesmo diretório:
plugins/
FreeMinecraftModels/
models/
torch_01.fmmodel
torch_01.yml <-- configuração de script para torch_01
scripts/
invulnerable.lua <-- referenciado por torch_01.yml
O arquivo de configuração .yml é o que conecta um modelo aos seus scripts.
Formato do Arquivo de Configuração
O arquivo de configuração YAML que fica ao lado de um arquivo de modelo tem dois campos:
isEnabled: true
scripts:
- invulnerable.lua
| Campo | Tipo | Padrão | Notas |
|---|---|---|---|
isEnabled | boolean | true | Se os scripts estão ativos para este prop |
scripts | lista de strings | [] | Nomes de arquivos .lua de scripts na pasta scripts/ |
Você pode anexar múltiplos scripts ao mesmo prop. Cada script é sua própria instância independente.
Geração Preguiçosa de Configuração
Quando um prop spawna e nenhum arquivo .yml irmão existe, o FMM cria automaticamente um arquivo de configuração padrão com isEnabled: true e uma lista vazia scripts:. Isso acontece de forma assíncrona, então o prop não terá scripts no seu primeiro spawn -- apenas depois que a configuração é criada e você a edita para adicionar nomes de arquivo de scripts.
Isso significa:
- Coloque seu arquivo de modelo em
models/ - Spawne o prop uma vez (FMM cria o
.ymlautomaticamente) - Edite o
.ymlgerado para adicionar os nomes dos seus scripts - Respawne o prop ou recarregue (scripts agora estão ativos)
Referência de Hooks
Cada arquivo 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 correspondente é disparado.
| Hook | Dispara quando | Notas |
|---|---|---|
on_spawn | O prop é spawnado no mundo | Roda uma vez quando o script é vinculado |
on_game_tick | Uma vez a cada tick do servidor (50 ms) | Apenas ativo se o script definir este hook |
on_destroy | O prop é removido do mundo | Hook de limpeza |
on_left_click | Um jogador clica com botão esquerdo (ataca) o prop | context.event é o evento de dano |
on_right_click | Um jogador clica com botão direito no prop | context.event é o evento de interação |
on_projectile_hit | Um projétil atinge o prop | context.event é o evento de impacto de projétil |
on_zone_enter | Um jogador entra em uma zona monitorada | Requer que um monitoramento de zona esteja configurado |
on_zone_leave | Um jogador sai de uma zona monitorada | Requer que um monitoramento de zona esteja configurado |
Referência de Hooks de Item
Scripts de item retornam uma tabela assim como scripts de prop, com api_version = 1 e funções de hook. Os seguintes hooks estão disponíveis para scripts de item. Todos os hooks de item recebem context com context.player, context.item e (onde aplicável) context.event.
Hooks de Combate
| Hook | Dispara quando | Notas |
|---|---|---|
on_attack_entity | O jogador ataca uma entidade enquanto segura o item | context.event é o evento de dano |
on_kill_entity | O jogador mata uma entidade enquanto segura o item | context.event é o evento de morte |
on_take_damage | O jogador recebe dano enquanto o item está equipado | context.event é o evento de dano |
on_shield_block | O jogador bloqueia dano com um escudo | context.event é o evento de dano |
on_shoot_bow | O jogador dispara um arco | context.event é o evento de disparo de arco |
on_projectile_hit | Um projétil disparado pelo jogador atinge algo | context.event é o evento de impacto de projétil |
on_projectile_launch | O jogador lança um projétil | context.event é o evento de lançamento de projétil |
Hooks de Interação
| Hook | Dispara quando | Notas |
|---|---|---|
on_right_click | O jogador clica com botão direito enquanto segura o item | context.event é o evento de interação |
on_left_click | O jogador clica com botão esquerdo enquanto segura o item | context.event é o evento de interação |
on_shift_right_click | O jogador faz shift+clique direito enquanto segura o item | context.event é o evento de interação |
on_shift_left_click | O jogador faz shift+clique esquerdo enquanto segura o item | context.event é o evento de interação |
on_interact_entity | O jogador clica com botão direito em uma entidade enquanto segura o item | context.event é o evento de interação com entidade |
Hooks de Equipamento
| Hook | Dispara quando | Notas |
|---|---|---|
on_equip | O item é equipado (movido para um slot ativo) | Bom lugar para inicializar estado |
on_unequip | O item é desequipado (movido para fora de um slot ativo) | Bom lugar para limpeza |
on_swap_hands | O jogador troca o item entre mão principal e secundária | context.event é o evento de troca |
on_drop | O jogador dropa o item | context.event é o evento de drop |
Hooks Utilitários
| Hook | Dispara quando | Notas |
|---|---|---|
on_break_block | O jogador quebra um bloco enquanto segura o item | context.event é o evento de quebra de bloco |
on_consume | O jogador consome o item (comida/poção) | context.event é o evento de consumo |
on_item_damage | O item sofre dano de durabilidade | context.event é o evento de dano ao item |
on_fish | O jogador usa uma vara de pescar | context.event é o evento de pesca |
on_death | O jogador morre enquanto o item está equipado | context.event é o evento de morte |
Hook de Ciclo de Vida
| Hook | Dispara quando | Notas |
|---|---|---|
on_game_tick | A cada tick do servidor enquanto o item está equipado | Use com moderação -- roda 20 vezes por segundo |
Contrato Mínimo do Arquivo
Cada script Lua de prop deve return uma tabela.
Campos de Nível Superior Obrigatórios e Opcionais
| Campo | Obrigatório | Tipo | Notas |
|---|---|---|---|
api_version | Sim | Number | Atualmente deve ser 1 |
priority | Não | Number | Prioridade de execução. Valores menores rodam primeiro. Padrão 0 |
| chaves de hook suportadas | Não | Function | Deve usar um dos nomes exatos de hook listados na Referência de Hooks |
Regras de Validação
- O arquivo deve retornar uma tabela.
api_versioné obrigatório e atualmente deve ser1.prioritydeve ser numérico se presente.- Cada chave extra de nível superior 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.
Seu Primeiro Script de Prop Funcional, Construído Devagar
Antes do Passo 1: Configure a Configuração
- Coloque seu arquivo de modelo (ex:
my_prop.fmmodel) emplugins/FreeMinecraftModels/models/ - Spawne o prop uma vez para gerar a configuração
.yml - Crie seu arquivo de script em
plugins/FreeMinecraftModels/scripts/first_test.lua - Edite
plugins/FreeMinecraftModels/models/my_prop.yml:
isEnabled: true
scripts:
- first_test.lua
- Respawne o prop ou recarregue o servidor
Passo 1: Faça o Arquivo Carregar
return {
api_version = 1,
on_spawn = function(context)
end
}
Se isso carregar sem erros no console, você provou:
- O arquivo é Lua válido
- O FMM o encontrou na pasta
scripts/ - A configuração o referencia corretamente
- A forma da tabela retornada está correta
Passo 2: Faça o Prop Fazer Uma Coisa Visível
return {
api_version = 1,
on_spawn = function(context)
context.log:info("Script do prop carregado para: " .. (context.prop.model_id or "unknown"))
end
}
Verifique o console do servidor. Se você vir a mensagem de log, seu hook está disparando.
Passo 3: Reaja ao Clique de um Jogador
return {
api_version = 1,
on_right_click = function(context)
context.log:info("Prop foi clicado com botão direito!")
end
}
Clique com o botão direito no prop no jogo. Se o console mostrar a mensagem, o hook de clique está funcionando.
Passo 4: Cancele 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 pré-fabricado invulnerable.lua. Ele cancela o evento de dano para que o armor stand de suporte do prop não possa ser destruído.
Passo 5: Reproduza uma Animação ao Clicar
return {
api_version = 1,
on_right_click = function(context)
context.prop:play_animation("open", true, false)
end
}
Isso reproduz a animação "open" no modelo do prop, com blending 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 te entrega cada vez que algo acontece -- ele contém tudo que você 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 = seu próprio armazenamento persistente
-- context.log = logging no console
-- context.scheduler = tarefas atrasadas e repetitivas
-- context.zones = criação e monitoramento de zonas espaciais
end
Você não cria context você mesmo -- o FMM o cria e o passa para seu hook.
context é criado novo para cada chamada de hook, exceto context.state que persiste durante toda a vida do prop. Isso significa que você pode armazenar dados em context.state e lê-los de volta mais tarde em um hook diferente.
APIs Principais do context
Aqui está um resumo do que está disponível. Para detalhes completos, veja API de Props.
-
context.prop-- A entidade prop. Fornecemodel_id,current_location,play_animation()estop_animation(). -
context.event-- O evento Bukkit que acionou este hook. Disponível emon_left_click,on_right_clickeon_projectile_hit. Fornececancel(),uncancel()eis_cancelled. Énilem hooks que não têm evento (comoon_spawneon_game_tick). -
context.state-- Uma tabela Lua simples que persiste durante a vida do prop. Use para armazenar flags, estados de alternância, IDs de tarefas e qualquer coisa que precise lembrar entre hooks. -
context.log-- Logging no console comlog:info(msg),log:warn(msg)elog:error(msg). -
context.scheduler-- Tarefas atrasadas e repetitivas comscheduler:run_later(ticks, callback)escheduler:run_repeating(delay, interval, callback). Callbacks recebem um context novo. Cancele tarefas comscheduler:cancel(taskId). -
context.world-- Interação com o mundo: partículas, sons, consultas de blocos, raios, entidades próximas. Veja API de Props para a lista completa de métodos. -
context.zones-- Crie e monitore zonas espaciais (esferas, cilindros, cuboides). Veja API de Props para a lista completa de métodos.
Sintaxe de Método: : vs .
Em Lua, object:method(arg) é uma abreviação para object.method(object, arg). A API do FMM aceita ambas as formas:
context.log:info("hello")
context.log.info("hello") -- mesma coisa
Toda a documentação usa : de forma consistente.
Templates Iniciais para Copiar e Colar
Menor Script de Prop Válido
return {
api_version = 1,
on_spawn = function(context)
end
}
Template de Prop Invulnerável
return {
api_version = 1,
on_left_click = function(context)
if context.event then
context.event.cancel()
end
end
}
Template 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
}
Menor Script de Item Válido
return {
api_version = 1,
on_equip = function(context)
context.log:info("Item equipped by " .. context.player.name)
end
}
Template de Item com Ação de Clique Direito
return {
api_version = 1,
on_equip = function(context)
context.state.on_cooldown = false
end,
on_right_click = function(context)
if context.state.on_cooldown then return end
if context.event then context.event:cancel() end
-- Your action here
context.player:send_message("&aAbility activated!")
context.state.on_cooldown = true
context.scheduler:run_later(40, function()
context.state.on_cooldown = false
end)
end
}
Layout de Arquivo 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 novo script de prop do zero, use esta ordem:
- Crie o arquivo
.luae façaon_spawnfuncionar. - Adicione o nome do script à configuração
.ymldo prop. - Mude para o hook real que deseja (ex:
on_right_click). - Adicione uma mensagem de log primeiro, antes de animações ou efeitos.
- Adicione um efeito real (animação, som, partícula).
- Só depois disso, adicione auxiliares, state, lógica de scheduler ou zonas.
Essa ordem torna a depuração dramaticamente mais fácil porque apenas uma coisa muda de cada vez.
Scripts Pré-fabricados
O FMM vem com dois scripts Lua pré-fabricados:
invulnerable.lua-- Cancela eventos de dano de clique esquerdo, tornando o prop indestrutível. Este é o script de prop útil mais simples.pickupable.lua-- Permite que jogadores peguem um prop ao acertá-lo três vezes. Cada acerto reproduz uma animação de dano no prop, e no terceiro acerto o prop é removido e dropa seu item de colocação para o jogador coletar.
Você pode encontrar mais exemplos na página Exemplos e Padrões.
Sandbox Lua
Scripts de props rodam dentro do mesmo ambiente LuaJ sandboxado que o EliteMobs. As restrições do sandbox são idênticas. Para a lista completa de globais removidos e funções de biblioteca padrão disponíveis, veja a página Hooks e Ciclo de Vida do EliteMobs.
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,printe mais
print escreve no console do servidor, mas prefira context.log:info(msg) para saída. Mensagens de log são prefixadas com o nome do arquivo do script, facilitando rastrear qual script produziu a mensagem.
Próximos Passos
- API de Props -- referência completa de
context.prop,context.event,context.world,context.zonesecontext.scheduler - Exemplos e Padrões -- scripts completos com explicações
- Solução de Problemas -- problemas comuns, dicas de depuração e checklist de QC
Se você também escreve poderes Lua para EliteMobs, as APIs compartilhadas (context.world, context.zones, context.scheduler, context.state, context.log) funcionam de forma idêntica. Veja a documentação Lua do EliteMobs para as APIs específicas de bosses.