Pular para o conteúdo principal

Scripting Lua: API de Props

Esta página cobre todas as APIs disponíveis para scripts de props do FreeMinecraftModels: context.prop, context.event, context.world, context.zones, context.scheduler, context.state e context.log. Se você é novo em scripting de props, comece primeiro com Primeiros Passos.


context.prop

A tabela prop fornece informações sobre a entidade do prop e métodos para controlar suas animações. Ela é reconstruída a cada chamada de hook.

Campos

CampoTipoNotas
prop.model_idstringO nome do modelo blueprint (ex.: "torch_01")
prop.current_locationlocation tableA posição do prop no momento em que o contexto foi construído

A tabela de localização possui os campos padrão: x, y, z, world, yaw, pitch.

Exemplo: lendo informações do prop
return {
api_version = 1,

on_spawn = function(context)
context.log:info("Prop spawned: " .. (context.prop.model_id or "unknown"))
local loc = context.prop.current_location
if loc then
context.log:info("Location: " .. loc.x .. ", " .. loc.y .. ", " .. loc.z)
end
end
}

prop:play_animation(name, blend, loop)

Reproduz uma animação nomeada no modelo do prop.

ParâmetroTipoPadrãoNotas
namestringobrigatórioO nome da animação conforme definido no arquivo do modelo
blendbooleantrueSe deve mesclar com a animação atual
loopbooleantrueSe a animação repete em loop

Retorna true se a animação foi encontrada e iniciada, false caso contrário.

Exemplo
return {
api_version = 1,

on_right_click = function(context)
local success = context.prop:play_animation("open", true, false)
if not success then
context.log:warn("Animation 'open' not found on this model!")
end
end
}

prop:stop_animation()

Para todas as animações sendo reproduzidas atualmente no prop.

Não recebe parâmetros.

Exemplo
return {
api_version = 1,

on_right_click = function(context)
context.prop:stop_animation()
end
}

context.event

Dados do evento para o hook atual. Disponível em on_left_click, on_right_click e on_projectile_hit. Retorna nil em hooks que não possuem evento associado (on_spawn, on_game_tick, on_destroy, on_zone_enter, on_zone_leave).

Campos e métodos

Campo ou métodoTipoNotas
event.is_cancelledbooleanSe o evento está atualmente cancelado
event.cancel()functionCancela o evento (ex.: impede dano ou interação)
event.uncancel()functionReverte o cancelamento de um evento previamente cancelado
info

Nem todos os eventos são canceláveis. Se o evento Bukkit subjacente não implementa Cancellable, event.cancel() e event.uncancel() não estarão presentes e event.is_cancelled será sempre false.

Exemplo: Tornando um prop invulnerável

Exemplo
return {
api_version = 1,

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

Exemplo: Verificando o estado de cancelamento

Exemplo
return {
api_version = 1,

on_left_click = function(context)
if context.event and not context.event.is_cancelled then
context.event.cancel()
context.log:info("Damage cancelled!")
end
end
}
cuidado

Dentro de callbacks agendados (scheduler:run_later, scheduler:run_repeating), context.event é sempre nil. A modificação de eventos só pode acontecer durante o próprio hook do evento.


context.world

A tabela world fornece métodos para consultar e interagir com o mundo do Minecraft. Ela é construída a partir do mundo atual do prop.

API compartilhada

A API context.world é compartilhada com o EliteMobs. Props do FMM usam a mesma tabela world do Magmacore que os bosses do EliteMobs. Os métodos documentados aqui são os disponíveis na implementação base do Magmacore. Para a referência completa, consulte a página EliteMobs World & Environment -- os métodos listados lá como parte da API base context.world também estão disponíveis no FMM.

world.name

Um campo string contendo o nome do mundo.


world:get_block_at(x, y, z)

Retorna o nome do material do bloco nas coordenadas fornecidas como uma string em minúsculas (ex.: "stone", "air").

ParâmetroTipoNotas
xintCoordenada X do bloco
yintCoordenada Y do bloco
zintCoordenada Z do bloco
Exemplo
return {
api_version = 1,

on_spawn = function(context)
local loc = context.prop.current_location
if loc then
local block = context.world:get_block_at(
math.floor(loc.x),
math.floor(loc.y) - 1,
math.floor(loc.z)
)
context.log:info("Prop is standing on: " .. block)
end
end
}

world:spawn_particle(particle, x, y, z, count, dx, dy, dz, speed)

Gera partículas em uma localização.

ParâmetroTipoPadrãoNotas
particlestringobrigatórioNome do enum Particle do Bukkit, em MAIÚSCULAS (ex.: "FLAME", "DUST")
xnumberobrigatórioCoordenada X
ynumberobrigatórioCoordenada Y
znumberobrigatórioCoordenada Z
countint1Número de partículas
dxnumber0Dispersão/deslocamento em X
dynumber0Dispersão/deslocamento em Y
dznumber0Dispersão/deslocamento em Z
speednumber0Velocidade das partículas
Exemplo
return {
api_version = 1,

on_right_click = function(context)
local loc = context.prop.current_location
if loc then
context.world:spawn_particle("HEART", loc.x, loc.y + 1, loc.z, 5, 0.3, 0.3, 0.3, 0)
end
end
}

world:play_sound(sound, x, y, z, volume, pitch)

Reproduz um som em uma localização.

ParâmetroTipoPadrãoNotas
soundstringobrigatórioNome do enum Sound do Bukkit, em MAIÚSCULAS (ex.: "ENTITY_EXPERIENCE_ORB_PICKUP")
xnumberobrigatórioCoordenada X
ynumberobrigatórioCoordenada Y
znumberobrigatórioCoordenada Z
volumenumber1.0Volume
pitchnumber1.0Tom
Exemplo
return {
api_version = 1,

on_right_click = function(context)
local loc = context.prop.current_location
if loc then
context.world:play_sound("BLOCK_NOTE_BLOCK_PLING", loc.x, loc.y, loc.z, 1.0, 1.2)
end
end
}

world:strike_lightning(x, y, z)

Invoca um raio em uma localização (visual e causando dano).

ParâmetroTipoNotas
xnumberCoordenada X
ynumberCoordenada Y
znumberCoordenada Z
Exemplo
return {
api_version = 1,

on_projectile_hit = function(context)
local loc = context.prop.current_location
if loc then
context.world:strike_lightning(loc.x, loc.y, loc.z)
end
end
}

world:get_time()

Retorna o horário atual do mundo em ticks.


world:set_time(ticks)

Define o horário do mundo.

ParâmetroTipoNotas
ticksintHorário do mundo (0 = amanhecer, 6000 = meio-dia, 13000 = noite, 18000 = meia-noite)

world:get_nearby_entities(x, y, z, radius)

Retorna um array de tabelas wrapper de entidades para todas as entidades vivas dentro de uma caixa delimitadora centrada nas coordenadas fornecidas.

ParâmetroTipoNotas
xnumberCentro X
ynumberCentro Y
znumberCentro Z
radiusnumberRaio de busca (usado como meia-extensão nos três eixos)
Exemplo
return {
api_version = 1,

on_right_click = function(context)
local loc = context.prop.current_location
if loc then
local entities = context.world:get_nearby_entities(loc.x, loc.y, loc.z, 10)
context.log:info("Found " .. #entities .. " entities nearby")
end
end
}

world:get_nearby_players(x, y, z, radius)

Retorna um array de tabelas wrapper de jogadores para todos os jogadores dentro de uma caixa delimitadora centrada nas coordenadas fornecidas.

ParâmetroTipoNotas
xnumberCentro X
ynumberCentro Y
znumberCentro Z
radiusnumberRaio de busca
Exemplo
return {
api_version = 1,

on_right_click = function(context)
local loc = context.prop.current_location
if loc then
local players = context.world:get_nearby_players(loc.x, loc.y, loc.z, 20)
for i = 1, #players do
context.log:info("Nearby player: " .. (players[i].name or "unknown"))
end
end
end
}

context.zones

A tabela zones permite criar zonas espaciais e monitorá-las para eventos de entrada/saída de jogadores. As zonas são vinculadas à instância do script e limpas automaticamente quando o prop é removido.

zones:create_sphere(x, y, z, radius)

Cria uma zona esférica centrada nas coordenadas fornecidas. Retorna um identificador numérico de zona.

ParâmetroTipoNotas
xnumberCentro X
ynumberCentro Y
znumberCentro Z
radiusnumberRaio da esfera

zones:create_cylinder(x, y, z, radius, height)

Cria uma zona cilíndrica. Retorna um identificador numérico de zona.

ParâmetroTipoNotas
xnumberCentro X
ynumberCentro Y (base)
znumberCentro Z
radiusnumberRaio do cilindro
heightnumberAltura do cilindro

zones:create_cuboid(x, y, z, xSize, ySize, zSize)

Cria uma zona em forma de cuboide. Retorna um identificador numérico de zona.

ParâmetroTipoNotas
xnumberCentro X
ynumberCentro Y
znumberCentro Z
xSizenumberMeia-extensão em X
ySizenumberMeia-extensão em Y
zSizenumberMeia-extensão em Z

zones:watch(handle, onEnterCallback, onLeaveCallback)

Começa a monitorar uma zona para eventos de entrada/saída de jogadores. Quando um jogador entra ou sai da zona, o hook correspondente é disparado (on_zone_enter ou on_zone_leave).

ParâmetroTipoNotas
handleintIdentificador de zona de uma chamada create_*
onEnterCallbackfunction ou nilChamado quando um jogador entra na zona
onLeaveCallbackfunction ou nilChamado quando um jogador sai da zona

Retorna true se o monitoramento foi configurado com sucesso, nil se o identificador de zona era inválido.

info

Os monitoramentos de zona são verificados a cada tick do servidor contra todos os jogadores no mesmo mundo. Mantenha a quantidade de zonas razoável para evitar sobrecarga de desempenho.


zones:unwatch(handle)

Para o monitoramento de uma zona e limpa seus recursos.

ParâmetroTipoNotas
handleintIdentificador de zona a parar de monitorar

Exemplo: Zona de ativação por proximidade

Exemplo
return {
api_version = 1,

on_spawn = function(context)
local loc = context.prop.current_location
if loc == nil then return end

-- Create a sphere zone around the prop
local handle = context.zones:create_sphere(loc.x, loc.y, loc.z, 5)

-- Watch for player enter/leave
context.zones:watch(
handle,
function(player)
context.log:info("Player entered zone!")
end,
function(player)
context.log:info("Player left zone!")
end
)

-- Store handle so we can clean up later if needed
context.state.zone_handle = handle
end,

on_destroy = function(context)
if context.state.zone_handle then
context.zones:unwatch(context.state.zone_handle)
end
end
}

context.scheduler

O scheduler permite executar tarefas atrasadas e repetitivas. Todas as tarefas pertencem à instância do script e são canceladas automaticamente quando o prop é removido.

scheduler:run_later(ticks, callback)

Executa um callback uma vez após um atraso. Retorna um ID de tarefa numérico.

ParâmetroTipoNotas
ticksintAtraso em ticks do servidor (20 ticks = 1 segundo)
callbackfunctionChamado com um context novo quando o atraso expira
Exemplo
return {
api_version = 1,

on_right_click = function(context)
context.log:info("Something will happen in 2 seconds...")

context.scheduler:run_later(40, function(delayed_context)
local loc = delayed_context.prop.current_location
if loc then
delayed_context.world:spawn_particle("EXPLOSION_EMITTER", loc.x, loc.y, loc.z, 1)
end
end)
end
}

scheduler:run_repeating(delay, interval, callback)

Executa um callback repetidamente em um intervalo fixo. Retorna um ID de tarefa numérico.

ParâmetroTipoNotas
delayintAtraso inicial em ticks antes da primeira execução
intervalintTicks entre cada execução subsequente
callbackfunctionChamado com um context novo a cada intervalo
Exemplo
return {
api_version = 1,

on_spawn = function(context)
-- Emit particles every second
context.state.particle_task = context.scheduler:run_repeating(0, 20, function(tick_context)
local loc = tick_context.prop.current_location
if loc then
tick_context.world:spawn_particle("FLAME", loc.x, loc.y + 1, loc.z, 3, 0.1, 0.1, 0.1, 0.02)
end
end)
end,

on_destroy = function(context)
if context.state.particle_task then
context.scheduler:cancel(context.state.particle_task)
end
end
}

scheduler:cancel(taskId)

Cancela uma tarefa agendada pelo seu ID.

ParâmetroTipoNotas
taskIdintO ID da tarefa retornado por run_later ou run_repeating
Sempre cancele tarefas repetitivas

Se você iniciar uma tarefa repetitiva, sempre cancele-a em on_destroy (ou quando não for mais necessária). Esquecer de cancelar deixa uma tarefa em segundo plano executando até que o prop seja removido do servidor, o que desperdiça desempenho e pode causar erros.


context.state

Uma tabela Lua simples que persiste durante toda a vida do prop. Use-a para armazenar flags, contadores, IDs de tarefas, estados de alternância e quaisquer dados que precise compartilhar entre hooks.

on_spawn = function(context)
context.state.is_open = false
context.state.click_count = 0
context.state.task_id = nil
end,

on_right_click = function(context)
context.state.click_count = (context.state.click_count or 0) + 1
end
info

Apenas context.state persiste entre chamadas de hooks. Todas as outras tabelas de contexto (context.prop, context.world, context.event, etc.) são reconstruídas a cada vez.


context.log

Métodos de log no console. As mensagens são prefixadas com o nome do arquivo do script no console do servidor.

MétodoNotas
log:info(message)Mensagem informativa
log:warn(message)Mensagem de aviso
log:error(message)Mensagem de erro (funcionalmente igual a warn)
Exemplo
return {
api_version = 1,

on_spawn = function(context)
context.log:info("Script loaded!")
end,

on_right_click = function(context)
context.log:warn("Prop was clicked -- this is a debug warning")
end
}

Modelo de execução

Um runtime por prop

Cada entidade prop que possui scripts atribuídos recebe sua própria instância independente de runtime Lua. Quando o prop é gerado, o FMM carrega o código-fonte Lua, avalia-o em um ambiente sandbox novo e armazena a tabela retornada. Quando o prop é removido, o runtime é encerrado.

Isso significa:

  • Variáveis locais declaradas no escopo do arquivo são privadas para aquela instância de prop.
  • context.state é completamente isolado entre instâncias de prop, mesmo que compartilhem o mesmo arquivo de script.

Propriedade de tarefas

Todas as tarefas criadas através de context.scheduler pertencem ao runtime que as criou. Quando um prop é removido:

  1. O runtime é encerrado.
  2. Todas as tarefas -- tanto as únicas quanto as repetitivas -- são automaticamente canceladas.
  3. Todos os monitoramentos de zona são limpos.

Orçamento de execução

Cada invocação de hook e cada invocação de callback é cronometrada. Se uma única chamada levar mais de 50 milissegundos, o script é desativado com um aviso no console:

[Lua] my_script.lua took 73ms in 'on_game_tick' (limit: 50ms) -- script disabled to prevent lag.

Para se manter dentro do orçamento:

  • Evite loops sem limite dentro de hooks.
  • Mantenha os handlers de on_game_tick leves -- eles executam a cada tick.
  • Use context.scheduler:run_repeating(...) para distribuir o trabalho entre ticks.

Próximos passos