Scripting Lua: Primeiros Passos
O que vai aprender
Esta pagina ensina a escrever o seu primeiro poder Lua para EliteMobs, desde um ficheiro vazio ate uma habilidade de boss funcional. No final, compreendera hooks, context, tempos de recarga e a estrutura geral de cada ficheiro de poder Lua.
Depois de se sentir confortavel com o basico, continue com as paginas complementares:
- Hooks e Ciclo de Vida -- nomes de hooks, ordem de execucao e disponibilidade do context
- Boss e Entidades -- as APIs
context.boss,context.player,context.playersecontext.entities - Mundo e Ambiente -- particulas, sons, relampagos, spawning e a API
context.world - Zonas e Alvos -- zonas Lua nativas, utilitarios de Script para alvos e as APIs
context.zones/context.script - Exemplos e Padroes -- poderes completos e funcionais para estudar e adaptar
- Enums e Valores -- links para os Javadocs do Spigot para Particle, Material, PotionEffectType e outras constantes de string
- Resolucao de Problemas -- erros comuns, dicas de depuracao e a checklist QC
Os ficheiros de poder Lua sao atualmente experimentais. Nomes de hooks, metodos auxiliares e comportamentos ainda podem mudar conforme o EliteMobs evolui, por isso teste cuidadosamente antes de usar num servidor de producao.
Lua nao substitui o sistema YAML eliteScript: existente.
- Use EliteScript quando quiser scripting declarativo baseado em YAML com as paginas existentes de Acoes, Alvos, Zonas, Condicoes, Tempos de Recarga e Vetores Relativos.
- Use ficheiros de poder Lua quando precisar de variaveis, loops, selecao aleatoria, funcoes auxiliares reutilizaveis, estado persistente por boss e um fluxo de programacao mais tradicional.
Lua tem o seu proprio sistema de alvos e zonas que usa os mesmos nomes de enum e conceitos familiares que ja conhece do EliteScript. A API Script Utilities (context.script) permite criar zonas, alvos e vetores relativos com os mesmos nomes de campo documentados nas paginas EliteScript.
O que sao poderes Lua
Poderes Lua sao ficheiros .lua autonomos que ficam na arvore normal de powers do EliteMobs e sao referenciados exatamente como ficheiros de poder normais.
Para que servem os poderes Lua
Os poderes Lua destacam-se quando precisa de:
- Rotacoes de ataque e selecao aleatoria de movimentos
- Estado persistente entre hooks com
context.state - Acoes atrasadas e repetidas sem construir tudo com esperas YAML
- Funcoes auxiliares personalizadas partilhadas num ficheiro
- Ramificacoes complexas que seriam inconvenientes em EliteScript puro
- Logica de boss que ainda quer reutilizar definicoes de alvos e zonas estilo EliteScript
Se o seu poder e principalmente "ativar evento, executar algumas acoes com script", os docs existentes de EliteScript continuam a ser a forma mais rapida e clara de o construir. Se o seu poder precisa de fluxo de programa real, Lua e a ferramenta para esse trabalho.
Para quem e esta pagina
Esta pagina foi escrita para tres tipos de leitores:
- Alguem que ja conhece EliteScript e quer aprender Lua sem aprender "programacao real" de uma so vez
- Alguem novo no scripting de EliteMobs que precisa de uma referencia completa com nomes exatos
- Alguem que usa IA para redigir poderes e precisa de detalhes suficientes para saber quando a IA inventou algo falso
Nao precisa de se tornar um programador Lua completo antes de escrever poderes uteis. Para a maioria dos poderes praticos de EliteMobs, so precisa de:
- Como colocar um hook valido na tabela retornada
- Como ler valores do
context - Como parar cedo com
if ... then return end - Como chamar alguns metodos auxiliares corretamente
- Como copiar as especificacoes corretas de alvos e zonas dos docs existentes de EliteScript
Modelo Mental: EliteScript vs. Lua
Se conhece EliteScript, esta comparacao e a forma mais rapida de entender poderes Lua:
| Se pensa em termos de EliteScript | Em Lua isso normalmente significa |
|---|---|
| Events | Nomes de hooks como on_spawn ou on_boss_damaged_by_player |
| Cooldowns | context.cooldowns (ver context.cooldowns abaixo) |
| Acoes | Chamadas diretas de metodos como context.world:spawn_particle_at_location(...) ou context.script:damage(...) |
| Alvos | context.script:target({...}) -- usa os nomes de campo de EliteScript Target |
| Zonas | context.script:zone({...}) ou auxiliares nativos context.zones -- ver Zonas e Alvos |
| Vetores relativos | context.script:relative_vector({...}) ou context.vectors |
| Fluxo do script | As suas proprias instrucoes if de Lua, funcoes auxiliares, temporizadores e estado |
A maior diferenca e esta:
- EliteScript diz o que deveria acontecer em YAML.
- Lua permite decidir quando, porque e qual ramo deveria executar usando codigo.
Se EliteScript parece "configuracao", Lua parece "configuracao mais tomada de decisao".
Mini introducao a Lua para autores EliteMobs
Esta e a sintaxe Lua minima que a maioria dos autores de poderes precisa.
Variaveis
Use local para guardar um valor:
local cooldown_key = "fire_burst"
local damage_multiplier = 1.5
local significa que a variavel pertence apenas a este ficheiro ou bloco.
Funcoes
Funcoes sao blocos reutilizaveis de logica:
local function warn_player(player)
player:send_message("&cMove!")
end
Mais tarde, pode chama-la:
warn_player(context.player)
Verificacoes if
Use if quando algo so deve acontecer as vezes:
if context.player == nil then
return
end
Isso significa "se nao ha jogador para este hook, parar aqui".
nil
nil significa "sem valor". E a versao Lua de "nao ha nada aqui".
Verificara frequentemente nil com:
if context.event ~= nil then
-- fazer algo com o evento
end
~= significa "nao e igual a".
Tabelas
Lua usa tabelas para varios fins:
- Listas
- Objetos com chaves nomeadas
- A definicao final do poder retornada
Exemplo de uma tabela com chaves nomeadas:
local particle = {
particle = "FLAME",
amount = 1,
speed = 0.05
}
Retornar a definicao do poder
No final do ficheiro, retorna uma tabela:
return {
api_version = 1,
on_spawn = function(context)
end
}
Essa tabela retornada e o ficheiro de poder.
Comentarios
Use -- para escrever uma nota para humanos:
-- Este cooldown impede o ataque de disparar a cada golpe
context.cooldowns:set_local(60, "fire_burst")
O seu primeiro poder funcional, construido passo a passo
Se e completamente novo, esta e a melhor progressao para a "primeira vitoria".
Antes do Passo 1: Guarde e anexe a um boss
Guarde o ficheiro Lua na pasta normal de poderes do EliteMobs, por exemplo:
plugins/
EliteMobs/
powers/
first_test.lua
Depois adicione esse nome de ficheiro a configuracao do boss usando a lista normal powers::
powers:
- first_test.lua
O loop completo para iniciantes e:
- Guardar o ficheiro em
plugins/EliteMobs/powers/ - Adicionar o nome do ficheiro
.luaa listapowers:do boss - Invocar ou recarregar esse boss
- Testar o hook que esta a construir
Se precisar de mais contexto sobre ficheiros de boss, listas de poderes ou como os bosses personalizados sao estruturados, veja Criar Bosses Personalizados.
Passo 1: Fazer o ficheiro carregar
return {
api_version = 1,
on_spawn = function(context)
end
}
Se isto carregar sem erros, ja provou:
- O ficheiro e Lua valido
- EliteMobs encontrou-o
- A forma da tabela retornada esta correta
on_spawne um nome de hook valido
Passo 2: Fazer o boss fazer algo visivel
return {
api_version = 1,
on_spawn = function(context)
context.boss:play_sound_at_self("entity.blaze.ambient", 1.0, 1.0)
end
}
Agora tem a prova mais importante para iniciantes: o seu hook esta a disparar.
Passo 3: Reagir ao golpe de um jogador
return {
api_version = 1,
on_boss_damaged_by_player = function(context)
if context.player == nil then
return
end
context.player:send_message("&eYou hit the boss.")
end
}
Isto ensina tres ideias fundamentais:
on_boss_damaged_by_playere o nome do hookcontext.playere o jogador envolvido nesse hookreturnsai cedo quando os dados necessarios estao em falta
Passo 4: Prevenir spam com um tempo de recarga
return {
api_version = 1,
on_boss_damaged_by_player = function(context)
if context.player == nil then
return
end
if not context.cooldowns:local_ready("hello_message") then
return
end
context.player:send_message("&eYou woke up the boss.")
context.cooldowns:set_local(60, "hello_message")
end
}
Este e o primeiro padrao genuinamente util que a maioria dos autores precisa. Se entender este padrao, ja pode construir muitos poderes praticos.
Passo 5: Adicionar um efeito real
return {
api_version = 1,
on_boss_damaged_by_player = function(context)
if context.player == nil then
return
end
if not context.cooldowns:local_ready("shock") then
return
end
context.player:send_message("&cStatic jumps from the boss into your armor!")
context.world:strike_lightning_at_location(context.player.current_location)
context.cooldowns:set_local(100, "shock")
end
}
Neste ponto, ja esta a escrever um poder real.
Primeiro fluxo de trabalho real
Ao construir um novo poder Lua do zero, use esta ordem:
- Criar o ficheiro e fazer
on_spawnfuncionar. - Mudar para o hook que realmente quer.
- Confirmar que o hook tem os dados esperados, como
context.playeroucontext.event. - Adicionar primeiro uma mensagem ou som, antes de dano ou particulas.
- Adicionar tempos de recarga.
- Adicionar um efeito de jogo.
- So depois disso, adicionar auxiliares, estado, logica de agendador ou zonas.
Essa ordem torna a depuracao dramaticamente mais facil porque so muda uma coisa de cada vez.
Onde ficam os ficheiros Lua
Coloque ficheiros .lua na mesma arvore de pastas que os ficheiros de poder .yml normais:
plugins/
EliteMobs/
powers/
mycoolpower.lua
attack_push.yml
subfolder/
myotherpower.lua
Os poderes Lua sao descobertos automaticamente a partir dos diretorios de poderes que o EliteMobs ja carrega.
Como os bosses referenciam poderes Lua
Os ficheiros de boss continuam a usar a lista normal powers::
powers:
- attack_push.yml
- mycoolpower.lua
Nao e necessario nenhum campo especial. Os poderes Lua nao sao carregados atraves de eliteScript:.
Regras de nomenclatura de ficheiros
- Os bosses referenciam poderes Lua pelo nome de ficheiro, nao pelo caminho da pasta.
- O EliteMobs atualmente regista os poderes Lua descobertos apenas pelo nome base.
- Evite nomes duplicados como
powers/fire.luaepowers/bosses/fire.lua, porque um pode sobrescrever o outro durante a descoberta.
Poderes Lua pre-fabricados
O EliteMobs vem com dezenas de poderes Lua pre-fabricados na pasta powers, como attack_fire.lua, frost_cone.lua, meteor_shower.lua e muitos mais. Sao excelentes referencias para estudar -- basta abrir qualquer ficheiro .lua no seu diretorio plugins/EliteMobs/powers/. Para retrocompatibilidade, os poderes pre-fabricados tambem sao registados sob os seus nomes .yml legados.
Contrato minimo do ficheiro
Cada poder Lua deve retornar uma tabela com return. Essa tabela e intencionalmente restrita.
Campos de nivel superior obrigatorios e opcionais
| Campo | Obrigatorio | Tipo | Notas |
|---|---|---|---|
api_version | Sim | Number | Atualmente deve ser 1 |
priority | Nao | Number | Prioridade de execucao. Valores mais baixos executam primeiro. Padrao e 0 |
| Chaves de hook suportadas | Nao | Function | Deve usar um dos nomes de hook exatos listados na Referencia de Hooks |
Regras de validacao
- O ficheiro deve retornar uma tabela.
api_versione obrigatorio e atualmente deve ser1.prioritydeve ser numerico se presente.- Cada chave de nivel superior adicional deve ser um nome de hook suportado.
- Cada chave de hook deve apontar para uma funcao.
- Chaves de nivel superior desconhecidas sao rejeitadas.
Isto significa que funcoes auxiliares e constantes locais devem ficar acima do return final, nao dentro da tabela retornada a menos que sejam hooks reais.
Templates para copiar e colar
Menor poder Lua valido
return {
api_version = 1,
on_spawn = function(context)
end
}
Template inicial recomendado
local ATTACK_COOLDOWN = "my_attack"
local function can_run_attack(context)
return context.cooldowns:local_ready(ATTACK_COOLDOWN)
and context.cooldowns:global_ready()
end
local function run_attack(context)
context.boss:play_sound_at_self("entity.blaze.shoot", 1.0, 1.0)
context.cooldowns:set_local(100, ATTACK_COOLDOWN)
context.cooldowns:set_global(20)
end
return {
api_version = 1,
priority = 0,
on_boss_damaged_by_player = function(context)
if context.player == nil then
return
end
if not can_run_attack(context) then
return
end
run_attack(context)
end
}
Layout para ficheiros maiores
local CONSTANT_NAME = "value"
local function helper_function(context)
end
local function another_helper(context, value)
end
return {
api_version = 1,
priority = 0,
on_spawn = function(context)
end,
on_enter_combat = function(context)
end,
on_boss_damaged_by_player = function(context)
end,
on_exit_combat = function(context)
end
}
Hooks
Hooks sao funcoes com nomes especiais na tabela que retorna. EliteMobs chama-os quando algo acontece -- o boss aparece, recebe dano, entra em combate, etc. Ja viu on_spawn e on_boss_damaged_by_player no tutorial acima.
Os hooks mais comuns para comecar sao on_spawn, on_boss_damaged_by_player, on_enter_combat e on_exit_combat. Para a lista completa de todos os hooks, que chaves de context estao disponiveis em cada um e como funciona a ordem de execucao, consulte Hooks e Ciclo de Vida.
O que e context?
Cada funcao de hook recebe um argumento chamado context. Pense nele como uma caixa de ferramentas que o EliteMobs lhe entrega cada vez que algo acontece -- contem tudo o que precisa para interagir com o boss, o jogador, o mundo, os tempos de recarga e mais.
on_boss_damaged_by_player = function(context)
-- context.boss = o boss que foi atingido
-- context.player = o jogador que o atingiu
-- context.world = ferramentas para gerar particulas, sons, etc.
-- context.cooldowns = gestao de tempos de recarga
-- context.state = o seu proprio armazenamento persistente
end
Voce nao cria context -- o EliteMobs cria-o e passa-o ao seu hook. Basta ler dele e chamar metodos nele.
context e criado de novo para cada chamada de hook, exceto context.state que persiste durante toda a vida do boss. Isto significa que pode armazenar dados em context.state e le-los mais tarde num hook diferente.
APIs chave de context
Aqui estao as APIs mais importantes que usara de context:
-
context.state-- Uma tabela Lua simples que persiste durante a vida do boss. Use-a para guardar numeros de fase, IDs de tarefas, flags e tudo o que precisa de lembrar entre hooks. Socontext.statepersiste -- todas as outras tabelas de context sao criadas de novo em cada chamada. -
context.log-- Registo na consola comlog:info(msg),log:warn(msg)elog:debug(msg). Inestimavel durante o desenvolvimento. -
context.cooldowns-- Tempos de recarga locais por poder e globais por boss. O metodo chave ecooldowns:check_local(key, ticks)que verifica E define um cooldown atomicamente. Consulte a pagina Hooks e Ciclo de Vida para a API completa de cooldowns. -
context.scheduler-- Tarefas atrasadas e repetidas comscheduler:run_after(ticks, callback)escheduler:run_every(ticks, callback). Os callbacks recebem um context fresco -- use sempre o parametro do callback, nao ocontextexterno. Cancele tarefas repetidas emon_exit_combat. Consulte Hooks e Ciclo de Vida para detalhes. -
context.boss/context.player-- O boss e o jogador envolvidos no evento atual. Consulte Boss e Entidades para todos os campos e metodos. -
context.world-- Gerar particulas, entidades, sons, relampagos, blocos. Consulte Mundo e Ambiente. -
context.zones/context.script-- Geometria de zonas, alvos, dano, particulas. Consulte Zonas e Alvos.
Sintaxe de metodos: : vs. .
Em Lua, object:method(arg) e uma abreviacao de object.method(object, arg). A API do EliteMobs aceita ambas as formas, por isso qualquer uma funciona:
context.cooldowns:set_local(60, "test")
context.cooldowns.set_local(60, "test") -- o mesmo
Toda a documentacao usa : de forma consistente.
Proximos passos
Agora que conhece o basico, explore o resto da documentacao de scripting Lua:
- Hooks e Ciclo de Vida -- nomes de hooks, ordem de execucao e que chaves de context estao disponiveis em cada hook
- Boss e Entidades --
context.boss,context.player,context.players,context.entitiesecontext.event - Mundo e Ambiente -- particulas, sons, relampagos, spawning e
context.world - Zonas e Alvos -- zonas Lua nativas, utilitarios de Script para alvos/zonas/particulas e vetores relativos
- Exemplos e Padroes -- poderes completos e funcionais com explicacoes
- Enums e Valores -- links para os Javadocs do Spigot para Particle, Material, PotionEffectType e mais
- Resolucao de Problemas -- erros comuns, dicas de depuracao e checklist QC
Para scripting baseado em YAML, as paginas de EliteScript continuam a ser a referencia canonica:
