Saltar para o conteúdo principal

Scripts Lua: resolução de problemas

Esta página cobre problemas comuns ao escrever ou diagnosticar scripts de elementos decorativos FMM, incluindo a geração da configuração quando necessária. Para scripts funcionais, consulte Exemplos e padrões. Se está a começar, consulte Primeiros passos.

Ambiente Lua do MagmaCore

O FMM usa ScriptInstance do MagmaCore. Consulte Motor de scripts Lua do MagmaCore para o isolamento, agendamento, zonas, API do mundo, tabelas de entidades e métodos de interface para jogadores. Os poderes de bosses e scripts de NPC do EliteMobs reutilizam o isolamento Lua, mas expõem tabelas de contexto próprias.


Problemas comuns​

1. Configuração não carregada ou script não associado​

Sintoma: o elemento aparece, mas não responde a cliques nem a outros eventos.

Causas e soluções:

  • Ainda não existe um .yml. O FMM tenta criá-lo de forma assíncrona na primeira criação do elemento, com valores predefinidos (ativo, sem scripts), sem substituir ficheiros existentes. Adicione os nomes dos scripts, execute /fmm reload com sucesso e coloque um novo elemento. Alterações a YAML e Lua exigem ambas uma recarga.

  • A configuração contém isEnabled: false. Abra o .yml junto do modelo e defina isEnabled: true.

  • A lista scripts: está vazia. Adicione os nomes dos ficheiros:

    isEnabled: true
    scripts:
    - my_script.lua
  • O nome do .yml não corresponde ao modelo. Ambos devem ter o mesmo nome base e diretório. Por exemplo, torch_01.fmmodel precisa de torch_01.yml.


2. Ficheiro de script não encontrado​

Sintoma: a consola apresenta [FMM Scripts] Script 'my_script.lua' not found in scripts/ folder.

Causas e soluções:

  • Diretório errado. Coloque os scripts em plugins/FreeMinecraftModels/scripts/, não junto do modelo.

  • Nome diferente. O nome no .yml deve corresponder ao ficheiro em scripts/, incluindo maiúsculas e minúsculas. A extensão .lua é recomendada na configuração, mas opcional: o FMM acrescenta-a se faltar.

  • Ficheiro ausente. Confirme que o .lua existe em scripts/.

  • Definição em cache ou nomes repetidos. O FMM procura scripts recursivamente quando inicializa o fornecedor, mas associa-os pelo nome do ficheiro, não pelo caminho relativo. Use nomes únicos entre subpastas. Após adicionar ou editar um ficheiro Lua, execute /fmm reload com sucesso; recriar o elemento não volta a ler o código Lua em cache.


3. O script não carrega​

Sintoma: não vê erros na consola, mas nenhum evento executa o script.

Procure erros de sintaxe Lua no registo do arranque. As causas mais comuns são:

  • Falta de end para terminar uma função ou condição if.
  • Parênteses sem correspondência.
  • Falta de uma vírgula entre funções de eventos na tabela devolvida.
  • Ficheiro sem extensão .lua.

As falhas de descoberta surgem como avisos de scripts inválidos ou retirados, ou como erros de carregamento. As falhas de eventos e funções agendadas usam um bloco [Lua] com o ficheiro e o contexto de execução; a linha só aparece se puder ser extraída da exceção.


4. Um evento nunca executa a função​

Sintoma: a mensagem de arranque que adicionou aparece, mas uma função de evento nunca é executada.

Confirme o nome exato na referência de eventos. Erros comuns:

Nome erradoNome correto
on_clickon_right_click ou on_left_click
on_interacton_right_click
on_hiton_left_click
on_tickon_game_tick
on_removeon_destroy (só é executado quando o elemento é removido definitivamente, não ao descarregar o chunk nem ao recarregar)
on_arrow_hiton_projectile_hit

Confirme que o modelo foi carregado, tem uma hitbox utilizável e nenhum listener de proteção cancelou a interação antes da função do elemento. Um elemento criado usa um suporte de armadura; alterar uma opção não torna clicável um modelo inválido ou por carregar.


5. Limite de tempo ou execução excedido​

Sintoma: a máquina virtual gera um erro Lua e interrompe uma chamada durante a execução, com uma destas mensagens:

Lua instruction budget exceeded (250000 instruction limit)
Lua CPU-time budget exceeded (50ms current-thread CPU limit)
Lua elapsed-time fallback budget exceeded (250ms fallback; current-thread CPU time unavailable)

Cada evento, função agendada ou avaliação de ficheiro pode executar até 250 000 instruções Lua ou consumir 50 ms de CPU da thread atual, conforme o primeiro limite atingido. As chamadas aninhadas partilham a mesma quota. A terceira mensagem só surge quando a JVM não disponibiliza medição de CPU por thread; nesse caso, o MagmaCore usa 250 ms de tempo decorrido. O script tentou fazer demasiado trabalho numa chamada. Causas comuns:

  • Percorrer demasiadas entidades em on_game_tick.
  • Criar demasiadas partículas por tick.
  • Executar ciclos pesados sem distribuir o trabalho por vários ticks.

Solução: limite a frequência do trabalho com context.cooldowns ou use scheduler:run_repeating() com um intervalo adequado em vez de on_game_tick.

O limite de instruções restringe os ciclos Lua. O tempo é verificado a cada 1024 instruções Lua e no retorno; estas verificações não interrompem um método Java/Bukkit bloqueante durante a chamada. Limite também o trabalho dentro de cada função agendada.


6. context.event é nil num evento de clique​

Isto não deve ocorrer normalmente em on_left_click e on_right_click, mas proteja sempre o acesso:

if context.event then
context.event.cancel()
end

Nas funções agendadas, context.event é sempre nil. Só pode modificar um evento dentro da própria função que o trata.


7. A animação não é reproduzida​

Sintoma: play_animation() devolve false ou não há alteração visível.

Causas e soluções:

  • Nome incorreto. Deve corresponder exatamente à animação no .bbmodel ou .fmmodel.

  • Modelo sem animações. Confirme que o ficheiro contém dados de animação.

  • Observador sem pacote ou fora do alcance. O jogador precisa do pacote de recursos atual e de estar dentro do alcance de visualização do modelo.

  • Pedido em espera ou suprimido. Passar true em blend usa uma única posição de espera, não uma transição gradual. Um pedido posterior pode substituí-lo e um ataque durante uma animação personalizada pode devolver true sem a interromper. Use os argumentos posicionais indicados em Animações e distinga um pedido aceite de uma imagem apresentada.


8. As partículas não aparecem​

  • Os nomes aceitam FLAME ou flame; a API normaliza maiúsculas e minúsculas antes de procurar a partícula Bukkit.
  • Confirme que a posição pertence a um chunk carregado. Sem jogadores próximos, o chunk pode estar descarregado.
  • Confirme que count é pelo menos 1.
  • Algumas partículas, como DUST, exigem dados adicionais que o spawn_particle() base pode não suportar. Use partículas normais como FLAME, HEART, HAPPY_VILLAGER, NOTE ou ENCHANT.

9. O som não é reproduzido​

  • São aceites nomes enum Bukkit, sem distinção de maiúsculas, ou chaves válidas como minecraft:block.note_block.harp e chaves de pacotes personalizados. O cliente precisa de ter o som no pacote.
  • Confirme as coordenadas: não devem ser todas zero nem NaN.
  • Confirme que o volume é superior a 0.

10. O estado é reiniciado inesperadamente​

context.state pertence a uma instância de script. As entradas separadas de scripts: do mesmo elemento não o partilham. Mantém-se enquanto a instância está ativa. Se parecer reiniciar:

  • O elemento pode ter sido removido e criado novamente, ou o seu chunk pode ter sido descarregado e carregado de novo. Cada criação ou carregamento do chunk produz uma nova instância. Guarde com prop:set_persistent_data os valores que tenham de sobreviver a isto.
  • Uma recarga bem-sucedida ou um erro de script pode ter encerrado a instância anterior. Consulte a consola; corrigir o ficheiro não reativa uma instância encerrada sem recarregar e voltar a associar o script.
  • Pode estar a consultar a variável de contexto errada numa função agendada. Use o parâmetro de contexto da própria função.

11. A biblioteca os não está disponível​

Sintoma: o script falha com um erro como attempt to index nil (os).

A biblioteca os foi completamente removida do ambiente isolado. Não pode usar os.time(), os.clock() nem outras funções os.

Solução: use context.world:get_time() para a hora do mundo ou conte o tempo decorrido com estado e contadores de ticks em on_game_tick. Para tempos de recarga, prefira context.cooldowns:check_local(key, ticks).


12. O script de item não é ativado​

O formato de scripts de itens equipados foi removido. Um item personalizado com uma lista scripts: não vazia ou encantamentos antigos sem espaço de nomes é ignorado e produz um diagnóstico. Substitua-o por uma definição atual de item personalizado, com encantamentos com espaço de nomes. Os elementos decorativos continuam a usar scripts:.

13. A definição do item está indisponível​

Procure o nome exato do ficheiro no aviso de arranque ou recarregamento. Um material indisponível, como um item de uma versão Minecraft mais recente, também faz ignorar a definição. Corrija-a ou substitua-a por uma compatível com a versão do servidor. O FMM não a reescreve nem inventa um material alternativo.

14. O evento funciona, mas os métodos de entidades falham​

Sintoma: um evento como on_right_click funciona, mas uma função agendada falha com attempt to call nil ao chamar entity:damage() ou entity:push().

Causa: context.world:get_nearby_entities() devolve todas as entidades no alcance, incluindo itens no chão, orbes de experiência e nuvens de efeitos de área. As entidades não vivas não têm métodos de entidades vivas como damage(), push() ou add_potion_effect().

Solução: verifique if entity.damage then antes de chamar esses métodos:

local entities = context.world:get_nearby_entities(x, y, z, radius)
for _, entity in ipairs(entities) do
if entity.damage then
-- Safe to call living entity methods
entity:damage(5.0)
entity:push(0, 0.5, 0)
end
end

15. Faltam dados do evento nas funções agendadas​

Sintoma: faltam dados do clique ou combate dentro de uma função de scheduler:run_later() ou scheduler:run_repeating().

Causa: as funções agendadas recebem um contexto novo, sem o evento Bukkit original nem o jogador do evento genérico de zona. context.event é sempre nil. Os scripts de elementos decorativos só recebem context.player nos eventos provocados por jogadores, como cliques e entrada/saída de zonas. Se precisarem do jogador mais tarde, devem guardá-lo a partir de context.player ou context.event.player durante o evento original.

Solução: use o contexto novo da função agendada para o estado e o mundo. Capture o jogador ou entidade antes do agendamento quando precisar daquele participante específico e confirme que continua válido.

on_right_click = function(context)
local clicked_player = context.player or (context.event and context.event.player)

context.scheduler:run_later(20, function(later_context)
-- Prop scripts should use a captured player when they need the clicker.
local player = later_context.player or clicked_player
if player and player.is_valid then
player:send_message("&aDelayed message!")
end
end)
end

Como é gerada a configuração quando necessária​

O processo de geração ajuda a explicar o comportamento dos elementos novos:

  1. Primeira criação: se não existir um .yml correspondente, o FMM cria-o numa thread em segundo plano. O ficheiro não fica disponível imediatamente.

  2. Predefinições: a configuração contém isEnabled: true e scripts: [].

  3. Primeira criação sem scripts: o elemento já foi criado quando a configuração é escrita, e a lista ainda está vazia. Nenhum script é associado nessa primeira vez.

  4. Editar, recarregar e recriar: adicione os nomes dos scripts e execute /fmm reload com sucesso. As definições, verificações de colocação e listas de scripts do menu usam o mesmo catálogo preparado. Um novo elemento usa esse catálogo; não volta a ler o YAML editado. Alterações a Lua também exigem recarga.

  5. Localização: o .yml fica no mesmo diretório e usa o mesmo nome base do modelo. Exemplo:

    • Modelo: plugins/FreeMinecraftModels/models/fountain.fmmodel
    • Configuração: plugins/FreeMinecraftModels/models/fountain.yml
Instalação rápida
  1. Coloque o modelo em models/.
  2. Coloque o script em scripts/.
  3. Crie o elemento uma vez para gerar o .yml.
  4. Adicione scripts: [my_script.lua] ao .yml.
  5. Recarregue para descobrir o ficheiro Lua, coloque um elemento novo e confirme a sua própria mensagem de arranque.

Interpretar mensagens de erro​

Os erros de eventos e funções agendadas produzem um bloco [Lua] com o ficheiro e o contexto de execução. A linha é incluída quando a exceção contém uma localização reconhecível no código. Os erros de descoberta e configuração podem usar outros avisos.

Exemplo:

[Lua] Error in 'my_door.lua' at line 12 during 'on_right_click':
[Lua] -> You tried to call a method or function that doesn't exist.
[Lua] -> Check the method name for typos, or make sure you're using ':' (colon) for method calls, not '.' (dot).
[Lua] -> Script has been disabled for this entity to prevent further errors.

O sistema explica erros Lua comuns em linguagem simples:

Erro Lua originalSignificado da mensagem
attempt to call nilTentou chamar um método ou função inexistente. Verifique o nome e o uso de : ou .
index expected, got nilTentou aceder a um campo num valor nil. Confirme que foi inicializado anteriormente
attempt to indexTentou aceder a uma propriedade num valor nil ou inválido
bad argumentA função recebeu um argumento do tipo errado. A mensagem compara o tipo esperado e o recebido
Limite excedidoLua instruction budget exceeded (250000 instruction limit) ou Lua CPU-time budget exceeded (50ms current-thread CPU limit): a chamada foi interrompida e a instância do script desativada
dica

Leia todo o bloco [Lua] antes de alterar o código. Geralmente identifica diretamente a origem do problema.


Não invente nomes de métodos​

A API Lua do FMM expõe um conjunto específico de métodos. Não pressuponha que existem abreviaturas ou nomes alternativos. Erros comuns:

  • context.prop:get_location() não existe. Use o campo context.prop.current_location.
  • context.prop:set_animation("open") não existe. Use context.prop:play_animation("open", true, true).
  • context.event:setCancelled(true) não existe. Use context.event.cancel().
  • context.cooldowns:check_global(...) não existe. Use context.cooldowns:global_ready() e context.cooldowns:set_global(ticks) para tempos de recarga globais.
  • context.player só está definido nos eventos que envolvem um jogador, como cliques, entrada/saída de zonas e on_projectile_hit quando foi um jogador a disparar o projétil. Não representa um proprietário geral do elemento e é nil nos eventos de ciclo de vida e nas funções agendadas.
  • context.boss pertence ao EliteMobs. No FMM, use context.prop.

Consulte os métodos suportados na API de elementos decorativos e nas referências partilhadas que esta indica. Um nome plausível não prova que o método exista.


Sugestões de diagnóstico​

1. Use context.log:info() em cada etapa​

Adicione mensagens para observar a execução:

on_right_click = function(context)
context.log:info("Right click received!")
context.log:info("Event present: " .. tostring(context.event ~= nil))
context.log:info("State is_open: " .. tostring(context.state.is_open))
end

2. Consulte a consola no arranque​

Adicione context.log:info("Prop script started") a on_spawn e coloque um elemento novo após recarregar. Procure a mensagem e eventuais erros de scripts ou configuração. O FMM não emite uma confirmação de sucesso para cada associação.

3. Confirme o caminho do modelo​

A configuração deve estar no mesmo diretório do modelo, com o mesmo nome base. Confirme:

  • Modelo: plugins/FreeMinecraftModels/models/my_model.fmmodel
  • Configuração: plugins/FreeMinecraftModels/models/my_model.yml

4. Verifique cada evento separadamente​

Num script complexo, adicione uma função de evento de cada vez e confirme que é executada antes de avançar.

5. Procure erros nos nomes dos eventos​

Um nome mal escrito é uma causa comum de falha. Um evento desconhecido faz rejeitar o script na validação. Consulte o erro na consola; não espere que as restantes funções desse ficheiro continuem a funcionar.


Percurso para principiantes​

Para aprender desde o início:

  1. Escreva um ficheiro com api_version = 1 e on_spawn que registe uma mensagem.
  2. Associe-o à configuração e confirme a mensagem.
  3. Adicione on_right_click e registe os cliques.
  4. Adicione on_left_click com context.event.cancel() para suprimir o dano predefinido do clique.
  5. Reproduza uma animação com o clique direito.
  6. Acrescente um som ao clique direito.
  7. Adicione estado e um comportamento alternável.
  8. Observe uma zona para detetar proximidade.
  9. Depois avance para scripts com vários eventos e tarefas agendadas.

Cada passo usa o anterior e permite verificar o resultado antes de continuar.


Próximos passos​