Pular para o conteúdo principal

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:

Recurso Experimental

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.

Relação com Lua do EliteMobs

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 ScriptInstance por 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 do model_id do prop. Para obter um item com as tags corretas, use /fmm giveitem <id> ou o menu de admin.
  • Contexto: Hooks de item recebem context com context.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()
dica

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
CampoTipoPadrãoNotas
isEnabledbooleantrueSe os scripts estão ativos para este prop
scriptslista 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:

  1. Coloque seu arquivo de modelo em models/
  2. Spawne o prop uma vez (FMM cria o .yml automaticamente)
  3. Edite o .yml gerado para adicionar os nomes dos seus scripts
  4. 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.

HookDispara quandoNotas
on_spawnO prop é spawnado no mundoRoda uma vez quando o script é vinculado
on_game_tickUma vez a cada tick do servidor (50 ms)Apenas ativo se o script definir este hook
on_destroyO prop é removido do mundoHook de limpeza
on_left_clickUm jogador clica com botão esquerdo (ataca) o propcontext.event é o evento de dano
on_right_clickUm jogador clica com 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 em uma zona monitoradaRequer que um monitoramento de zona esteja configurado
on_zone_leaveUm jogador sai de uma zona monitoradaRequer 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

HookDispara quandoNotas
on_attack_entityO jogador ataca uma entidade enquanto segura o itemcontext.event é o evento de dano
on_kill_entityO jogador mata uma entidade enquanto segura o itemcontext.event é o evento de morte
on_take_damageO jogador recebe dano enquanto o item está equipadocontext.event é o evento de dano
on_shield_blockO jogador bloqueia dano com um escudocontext.event é o evento de dano
on_shoot_bowO jogador dispara um arcocontext.event é o evento de disparo de arco
on_projectile_hitUm projétil disparado pelo jogador atinge algocontext.event é o evento de impacto de projétil
on_projectile_launchO jogador lança um projétilcontext.event é o evento de lançamento de projétil

Hooks de Interação

HookDispara quandoNotas
on_right_clickO jogador clica com botão direito enquanto segura o itemcontext.event é o evento de interação
on_left_clickO jogador clica com botão esquerdo enquanto segura o itemcontext.event é o evento de interação
on_shift_right_clickO jogador faz shift+clique direito enquanto segura o itemcontext.event é o evento de interação
on_shift_left_clickO jogador faz shift+clique esquerdo enquanto segura o itemcontext.event é o evento de interação
on_interact_entityO jogador clica com botão direito em uma entidade enquanto segura o itemcontext.event é o evento de interação com entidade

Hooks de Equipamento

HookDispara quandoNotas
on_equipO item é equipado (movido para um slot ativo)Bom lugar para inicializar estado
on_unequipO item é desequipado (movido para fora de um slot ativo)Bom lugar para limpeza
on_swap_handsO jogador troca o item entre mão principal e secundáriacontext.event é o evento de troca
on_dropO jogador dropa o itemcontext.event é o evento de drop

Hooks Utilitários

HookDispara quandoNotas
on_break_blockO jogador quebra um bloco enquanto segura o itemcontext.event é o evento de quebra de bloco
on_consumeO jogador consome o item (comida/poção)context.event é o evento de consumo
on_item_damageO item sofre dano de durabilidadecontext.event é o evento de dano ao item
on_fishO jogador usa uma vara de pescarcontext.event é o evento de pesca
on_deathO jogador morre enquanto o item está equipadocontext.event é o evento de morte

Hook de Ciclo de Vida

HookDispara quandoNotas
on_game_tickA cada tick do servidor enquanto o item está equipadoUse 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

CampoObrigatórioTipoNotas
api_versionSimNumberAtualmente deve ser 1
priorityNãoNumberPrioridade de execução. Valores menores rodam primeiro. Padrão 0
chaves de hook suportadasNãoFunctionDeve 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 ser 1.
  • priority deve 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

  1. Coloque seu arquivo de modelo (ex: my_prop.fmmodel) em plugins/FreeMinecraftModels/models/
  2. Spawne o prop uma vez para gerar a configuração .yml
  3. Crie seu arquivo de script em plugins/FreeMinecraftModels/scripts/first_test.lua
  4. Edite plugins/FreeMinecraftModels/models/my_prop.yml:
isEnabled: true
scripts:
- first_test.lua
  1. 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.

info

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. 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 que não têm evento (como on_spawn e on_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 com log:info(msg), log:warn(msg) e log:error(msg).

  • context.scheduler -- Tarefas atrasadas e repetitivas com scheduler:run_later(ticks, callback) e scheduler:run_repeating(delay, interval, callback). Callbacks recebem um context novo. Cancele tarefas com scheduler: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:

  1. Crie o arquivo .lua e faça on_spawn funcionar.
  2. Adicione o nome do script à configuração .yml do prop.
  3. Mude para o hook real que deseja (ex: on_right_click).
  4. Adicione uma mensagem de log primeiro, antes de animações ou efeitos.
  5. Adicione um efeito real (animação, som, partícula).
  6. 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, print e mais
dica

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

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.