Scripting Lua: API de Props e Ítems
Esta página cubre todas las APIs disponibles para los scripts de props e ítems de FreeMinecraftModels: context.prop, context.item, context.event, context.player, context.world, context.zones, context.scheduler, context.state, context.cooldowns y context.log. Si eres nuevo en scripting, empieza primero por Primeros Pasos.
context.prop
La tabla prop proporciona información sobre la entidad prop y métodos para controlar sus animaciones. FMM cachea esta tabla por prop por rendimiento; campos como current_location son perezosos/en vivo, así que las lecturas siguen reflejando el estado actual del prop.
Campos
| Campo | Tipo | Notas |
|---|---|---|
prop.model_id | string | El nombre del modelo blueprint (p. ej. "torch_01") |
prop.current_location | tabla de ubicación | La posición del prop en el momento en que se construyó el contexto |
La tabla de ubicación tiene los campos estándar: x, y, z, world, yaw, pitch.
Ejemplo: leyendo la info del 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)
Reproduce una animación nombrada en el modelo del prop.
| Parámetro | Tipo | Predeterminado | Notas |
|---|---|---|---|
name | string | requerido | El nombre de la animación como se define en el archivo del modelo |
blend | booleano | true | Si debe mezclar con la animación actual |
loop | booleano | true | Si la animación se repite |
Devuelve true si la animación se encontró y comenzó, false en caso contrario.
Ejemplo
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()
Detiene todas las animaciones que se están reproduciendo actualmente en el prop.
No toma parámetros.
Ejemplo
return {
api_version = 1,
on_right_click = function(context)
context.prop:stop_animation()
end
}
prop:hurt_visual()
Reproduce la animación visual de daño (destello rojo) en el prop sin causarle ningún daño real.
No toma parámetros.
Ejemplo
return {
api_version = 1,
on_left_click = function(context)
-- Destellar en rojo cuando reciba un golpe, pero sin recibir daño real
if context.event then
context.event.cancel()
end
context.prop:hurt_visual()
end
}
prop:pickup()
Elimina el prop del mundo y suelta un objeto de papel de colocación en su ubicación. Se puede hacer clic derecho con el objeto soltado sobre un bloque para volver a colocar el prop.
No toma parámetros.
Ejemplo
return {
api_version = 1,
on_right_click = function(context)
-- Permite que los jugadores recojan el prop con clic derecho
context.prop:pickup()
end
}
prop:mount(player)
Monta a un jugador en el primer asiento de mount point disponible en el prop. El modelo debe tener huesos de punto de montaje definidos.
| Parámetro | Tipo | Notas |
|---|---|---|
player | tabla de entidad | Una tabla de entidad de jugador (p. ej. desde context.player o context.event.player) |
Devuelve true cuando se encontró al jugador, el prop tiene puntos de montaje y la acción de montar quedó encolada. Devuelve false cuando esas referencias básicas no son válidas. Un retorno true no prueba que hubiera finalmente un asiento disponible cuando se ejecutó la acción encolada.
Ejemplo
return {
api_version = 1,
on_right_click = function(context)
local player = context.event and context.event.player
if player then
context.prop:mount(player)
end
end
}
prop:dismount(player)
Desmonta a un jugador de su asiento de mount point en el prop.
| Parámetro | Tipo | Notas |
|---|---|---|
player | tabla de entidad | Una tabla de entidad de jugador |
Devuelve true cuando se encontró al jugador, el prop tiene un gestor de montaje y la comprobación de desmontaje quedó encolada. Devuelve false cuando esas referencias básicas no son válidas.
Ejemplo
return {
api_version = 1,
on_right_click = function(context)
local player = context.event and context.event.player
if player then
-- Alternar montar/desmontar
local passengers = context.prop:get_passengers()
for i = 1, #passengers do
if passengers[i].uuid == player.uuid then
context.prop:dismount(player)
return
end
end
context.prop:mount(player)
end
end
}
prop:get_passengers()
Devuelve un array Lua de tablas de entidad para todos los pasajeros actuales en el prop.
No toma parámetros.
Ejemplo
return {
api_version = 1,
on_game_tick = function(context)
local passengers = context.prop:get_passengers()
if #passengers > 0 then
context.log:info("Prop has " .. #passengers .. " passenger(s)")
end
end
}
prop:has_mount_points()
Devuelve si este prop tiene huesos de punto de montaje definidos en su modelo.
No toma parámetros. Devuelve true o false.
Ejemplo
return {
api_version = 1,
on_right_click = function(context)
local player = context.event and context.event.player
if player and context.prop:has_mount_points() then
context.prop:mount(player)
end
end
}
prop:spawn_elitemobs_boss(filename, x, y, z)
Genera un jefe personalizado de EliteMobs en la ubicación dada. Requiere que EliteMobs esté instalado en el servidor.
| Parámetro | Tipo | Notas |
|---|---|---|
filename | string | El nombre de archivo del jefe personalizado (p. ej. "my_boss.yml") |
x | número | Coordenada X |
y | número | Coordenada Y |
z | número | Coordenada Z |
Devuelve una tabla de entidad viva para el jefe generado, o nil si EliteMobs no está instalado o el archivo del jefe no existe.
Ejemplo
return {
api_version = 1,
on_right_click = function(context)
local loc = context.prop.current_location
if loc then
local boss = context.prop:spawn_elitemobs_boss("dungeon_guardian.yml", loc.x, loc.y + 1, loc.z)
if boss then
context.log:info("Spawned boss: " .. (boss.name or "unknown"))
else
context.log:warn("Could not spawn boss -- is EliteMobs installed?")
end
end
end
}
prop:open_inventory(player, title, rows)
Abre una GUI de inventario de cofre persistente para el jugador. El contenido se guarda en el PersistentDataContainer del prop cuando se cierra el inventario, y se restaura cuando se abre de nuevo.
| Parámetro | Tipo | Predeterminado | Notas |
|---|---|---|---|
player | tabla de entidad | requerido | El jugador al que mostrar el inventario |
title | string | requerido | El título del inventario (soporta códigos de color &) |
rows | int | 3 | Número de filas (1-6, donde 6 = 54 ranuras = doble cofre) |
Devuelve true si el inventario se abrió, false en caso contrario.
prop:is_viewing_inventory(player)
Devuelve si el jugador dado tiene actualmente el inventario de este prop abierto.
| Parámetro | Tipo | Notas |
|---|---|---|
player | tabla de entidad | El jugador a comprobar |
Devuelve true o false.
Ejemplo: Animación de cierre cuando se cierra el inventario
context.state["task_" .. player.uuid] = context.scheduler:run_repeating(5, 5, function(tick_context)
if not tick_context.prop:is_viewing_inventory(player) then
tick_context.prop:play_animation("close", true, false)
tick_context.scheduler:cancel(tick_context.state["task_" .. player.uuid])
end
end)
prop:place_book(player)
Toma el libro escrito o escribible de la mano principal del jugador y lo almacena en el prop.
| Parámetro | Tipo | Notas |
|---|---|---|
player | tabla de entidad | El jugador que sostiene el libro |
Devuelve true si tiene éxito.
prop:read_book(player)
Abre el libro almacenado para que el jugador lo lea.
| Parámetro | Tipo | Notas |
|---|---|---|
player | tabla de entidad | El jugador al que mostrar el libro |
Devuelve true si se abrió un libro.
prop:take_book(player)
Devuelve el libro almacenado al inventario del jugador y lo elimina del prop.
| Parámetro | Tipo | Notas |
|---|---|---|
player | tabla de entidad | El jugador al que dar el libro |
Devuelve true si tiene éxito.
prop:has_book()
Devuelve si hay un libro almacenado en este prop. No toma parámetros.
prop:drop_inventory()
Suelta todo el contenido del inventario almacenado en la ubicación del prop como entidades de objeto, y luego limpia los datos almacenados. Cierra automáticamente el inventario para cualquier jugador que esté viéndolo actualmente.
No toma parámetros. Devuelve true si tiene éxito.
prop:drop_book()
Suelta el libro almacenado en la ubicación del prop como una entidad de objeto y limpia los datos del libro almacenados.
No toma parámetros. Devuelve true si tiene éxito.
prop:set_persistent_data(key, value)
Almacena un valor string en el PersistentDataContainer del armor stand del prop. Estos datos sobreviven a reinicios del servidor y descargas de chunks.
| Parámetro | Tipo | Notas |
|---|---|---|
key | string | Un nombre de clave único (almacenado internamente bajo fmm_lua_<key>) |
value | string | El valor a almacenar. Usa tostring() para números y booleanos. |
Devuelve true si tiene éxito, false si el prop no tiene un armor stand de respaldo.
prop:get_persistent_data(key)
Recupera un valor string previamente almacenado con set_persistent_data. Devuelve nil si la clave no se ha establecido.
| Parámetro | Tipo | Notas |
|---|---|---|
key | string | El nombre de clave usado en set_persistent_data |
Ejemplo: Estado de toggle persistente
return {
api_version = 1,
on_spawn = function(context)
local saved = context.prop:get_persistent_data("active")
context.state.active = saved == "true"
end,
on_right_click = function(context)
context.state.active = not context.state.active
context.prop:set_persistent_data("active", tostring(context.state.active))
end
}
context.item
La tabla item solo está disponible en scripts de objeto (no en scripts de prop). Proporciona información sobre el objeto personalizado y métodos para manipularlo. Esta tabla se reconstruye nueva para cada llamada de hook.
Los métodos de escritura del ítem como set_amount, consume, set_uses, set_name, set_lore y los helpers de uso de durabilidad encolan su mutación en el hilo principal de Bukkit y devuelven nil. Los métodos de lectura devuelven el estado del ítem equipado coincidente en el momento en que se ejecutan.
Campos
| Campo | Tipo | Notas |
|---|---|---|
item.id | string | El ID del tipo de objeto (el fmm_item_id de la configuración YML) |
item:material()
Devuelve el nombre del material del objeto como string (p. ej. "DIAMOND_SWORD", "STICK").
item:get_amount() / item:set_amount(n)
Obtiene o establece el tamaño de stack del objeto. set_amount(n) encola el cambio y devuelve nil.
| Parámetro | Tipo | Notas |
|---|---|---|
n | int | La nueva cantidad de stack |
item:consume(n)
Encola un decremento de la cantidad de stack del objeto en n (por defecto 1). Si la cantidad resultante es 0 o menor, el objeto se elimina del inventario del jugador. Devuelve nil.
| Parámetro | Tipo | Predeterminado | Notas |
|---|---|---|---|
n | int | 1 | Cantidad a consumir |
item:get_uses() / item:set_uses(n)
Obtiene o establece un contador de usos personalizado almacenado en el PersistentDataContainer del objeto. Es independiente de la durabilidad vanilla y puede usarse para implementar sistemas de durabilidad personalizada o cargas. set_uses(n) encola el cambio y devuelve nil.
| Parámetro | Tipo | Notas |
|---|---|---|
n | int | El nuevo conteo de usos |
item:get_name() / item:set_name(s)
Obtiene o establece el nombre de visualización del objeto. Soporta códigos de color con &. set_name(s) encola el cambio y devuelve nil.
| Parámetro | Tipo | Notas |
|---|---|---|
s | string | El nuevo nombre de visualización (p. ej. "&b&lFrost Sword") |
item:get_lore() / item:set_lore(table)
Obtiene o establece el lore del objeto. get_lore() devuelve una tabla de strings (uno por línea). set_lore() toma una tabla de strings, encola el cambio y devuelve nil.
| Parámetro | Tipo | Notas |
|---|---|---|
table | tabla | Array de strings, uno por línea de lore |
Ejemplo: Script de objeto que rastrea usos
return {
api_version = 1,
on_right_click = function(context)
local uses = context.item:get_uses()
if uses <= 0 then
context.player:send_message("&cThis item is out of charges!")
return
end
context.item:set_uses(uses - 1)
context.player:send_message("&aUsed! Charges remaining: " .. (uses - 1))
end
}
item:get_durability()
Devuelve una tabla con campos current y max que representan la durabilidad vanilla del objeto, o nil si el objeto no tiene barra de durabilidad.
Ejemplo
local dur = context.item:get_durability()
if dur then
context.player:send_message("Durability: " .. dur.current .. "/" .. dur.max)
end
item:get_durability_percentage()
Devuelve la durabilidad restante como una fracción de 0.0 a 1.0, o nil si el objeto no tiene barra de durabilidad.
item:use_durability(amount, can_break)
Encola una reducción de durabilidad vanilla por una cantidad fija y devuelve nil.
| Parámetro | Tipo | Predeterminado | Notas |
|---|---|---|---|
amount | int | requerido | Cuántos puntos de durabilidad consumir |
can_break | booleano | false | Si es true, el objeto se destruye cuando se agota la durabilidad. Si es false, la durabilidad se detiene en 1. |
item:use_durability_percentage(fraction, can_break)
Encola una reducción de durabilidad vanilla por un porcentaje de su máximo y devuelve nil.
| Parámetro | Tipo | Predeterminado | Notas |
|---|---|---|---|
fraction | número | requerido | Fracción de durabilidad máxima a consumir (p. ej. 0.1 = 10%) |
can_break | booleano | false | Si es true, el objeto se destruye cuando se agota la durabilidad. Si es false, la durabilidad se detiene en 1. |
context.event
Datos del evento para el hook actual. Disponible en hooks de clic, combate, interacción y de zona genérica para scripts de prop e ítems. Devuelve nil en hooks que no tienen evento asociado ni actor jugador (on_spawn, on_game_tick, on_destroy, on_equip).
Las tablas de referencia de hooks de más abajo indican el tipo de evento de Bukkit subyacente a modo de orientación. El envoltorio de Lua sigue exponiendo únicamente los campos y métodos listados aquí.
Campos y Métodos
| Campo o Método | Tipo | Notas |
|---|---|---|
event.player | tabla de entidad de jugador | El jugador que desencadenó el evento o cruzó el borde de una zona genérica vigilada. Disponible en los hooks de prop on_left_click, on_right_click, on_zone_enter y on_zone_leave, además de los hooks de ítem provocados por un jugador. Consulta Métodos de Entidad de Jugador para todos los campos y métodos. |
event.is_cancelled | booleano | Estado de cancelación en el momento en que se construyó el context. Este campo no se refresca tras llamar a cancel() o uncancel(). |
event.cancel() | función | Cancela el evento (p. ej. previene daño o interacción) |
event.uncancel() | función | Descancela un evento previamente cancelado |
cancel y uncancel ignoran lo que se les pase, así que context.event.cancel() y context.event:cancel() se comportan igual. Los scripts predefinidos que vienen con FMM usan la forma con dos puntos; esta página usa la forma con punto. Ninguna es más correcta que la otra.
No todos los eventos son cancelables. Si el evento Bukkit subyacente no implementa Cancellable, o si el hook es un hook de zona genérica sin un evento de Bukkit detrás, event.cancel() y event.uncancel() no estarán presentes y event.is_cancelled siempre será false.
Trata event.is_cancelled como una instantánea del estado inicial. Si tu propio script llama a event.cancel() o event.uncancel(), guarda tu propia marca local si necesitas recordar ese cambio más adelante en el mismo hook.
La tabla de evento actual de FMM no expone campos específicos de Bukkit como target, block, projectile o item. Usa context.player, context.event.player, player:get_target_entity(range), context.world:raycast(...) o consultas de entidades cercanas cuando necesites contexto adicional.
Ejemplo: Hacer un prop invulnerable
Ejemplo
return {
api_version = 1,
on_left_click = function(context)
if context.event then
context.event.cancel()
end
end
}
Ejemplo: Comprobando el estado de cancelación
Ejemplo
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
}
Dentro de callbacks programados (scheduler:run_later, scheduler:run_repeating), context.event siempre es nil. La modificación del evento solo puede ocurrir durante el propio hook del evento.
context.world
Esta es la API de world de FreeMinecraftModels/MagmaCore. Consulta context.world para la referencia completa.
Los props de FMM usan la misma tabla world de MagmaCore que los jefes de EliteMobs. Todos los métodos documentados en la página global (get_block_at, set_block_at, spawn_particle, play_sound, strike_lightning, get_time, set_time, get_nearby_entities, get_nearby_players, spawn_entity, get_highest_block_y, raycast, place_temporary_block, drop_item, spawn_firework) están disponibles en FMM. Consulta la API world de MagmaCore para detalles completos sobre world:raycast() (lanzar un rayo y detectar entidades/bloques impactados), world:place_temporary_block() (reemplazo temporal de bloques) y world:spawn_firework() (generar cohetes de fuegos artificiales con colores y formas personalizados). Los poderes de jefe de EliteMobs parten de la misma base world y añaden métodos con tabla de ubicación específicos de jefe para generar jefes, refuerzos, bloques que caen, bloques temporales y más; consulta EliteMobs World & Environment.
Añadidos al World Específicos de FMM
FreeMinecraftModels superpone tres ayudantes opcionales de botín de EliteMobs sobre context.world. Siempre están presentes, pero cada uno devuelve false y no hace nada cuando EliteMobs no está instalado:
| Método | Notas |
|---|---|
world:drop_elitemobs_procedural_loot(player, level, location?) | Suelta un objeto de EliteMobs generado proceduralmente para el jugador. Devuelve false cuando las caídas de objetos procedurales están desactivadas |
world:drop_elitemobs_random_loot(player, level, location?) | Tira las tablas de botín de EliteMobs para el jugador en el nivel indicado |
world:drop_elitemobs_custom_loot(player, file, level, location?) | Suelta para el jugador un archivo concreto de objeto personalizado de EliteMobs. Devuelve false cuando el archivo no se resuelve |
Las firmas completas están en la Referencia de la API de Lua. El equivalente del lado del prop para los jefes es prop:spawn_elitemobs_boss(...), documentado más arriba.
Métodos de Entidad de Jugador
Las tablas de entidad de jugador se devuelven desde context.player, context.event.player y context.world:get_nearby_players(). Los hooks genéricos de MagmaCore on_zone_enter / on_zone_leave establecen context.player y context.event.player al jugador que entra o sale.
Las tablas de entidad, los métodos de entidad viva, los métodos específicos de jugador y los métodos de UI de jugador son compartidos entre todos los plugins de Nightbreak. Consulta el Motor de Scripting Lua de MagmaCore para la referencia completa de FMM que cubre los campos base de entidad, campos y métodos de entidad viva, campos y métodos específicos de jugador, y Métodos de UI de Jugador. Los nuevos métodos de jugador incluyen player:get_target_entity() (targeting por raycast), player:get_eye_location(), player:get_look_direction(), player:send_block_change() (bloques falsos por jugador) y player:reset_block() -- consulta Métodos Específicos de Jugador para más detalles.
Campos de Entidad Específicos de FMM
Cada tabla de entidad construida dentro de un script de FMM obtiene estos campos extra automáticamente (a través del LuaEntityEnricher de FMM):
| Campo | Tipo | Notas |
|---|---|---|
entity.is_modeled | booleano | true si esta entidad Bukkit es la entidad subyacente de un ModeledEntity |
entity.is_prop | booleano | true si esta entidad es un armor stand que respalda un PropEntity |
entity.model | tabla o nil | Poblado solo cuando is_modeled = true (ver abajo) |
Cuando entity.model está presente, expone:
| Campo / Método | Notas |
|---|---|
model.model_id | El nombre del modelo blueprint (p. ej. "dragon") |
model.is_dynamic | true si es un DynamicEntity (adjunto a una entidad viva) |
model:play_animation(name, blend, loop) | Reproduce una animación nombrada. blend y loop tienen valor por defecto false en el puente de modelo de entidad. Devuelve true en caso de éxito |
model:stop_animations() | Detiene todas las animaciones actuales |
model:remove() | Elimina inmediatamente la entidad modelada y todos sus huesos |
on_right_click = function(context)
local player = context.event and context.event.player
if not player then return end
local target = player:get_target_entity(8)
if target and target.is_modeled then
target.model:play_animation("hurt", true, false)
end
end
Campos de Entidad de EliteMobs
Cuando EliteMobs está instalado, FMM reenvía al enricher de EliteMobs para que las mismas tablas de entidad también expongan:
| Campo | Tipo | Notas |
|---|---|---|
entity.is_elite | booleano | true si la entidad es rastreada por EliteMobs |
entity.is_custom_boss | booleano | true si es una configuración de jefe personalizado |
entity.is_significant_boss | booleano | true para jefes personalizados con healthMultiplier > 1 (filtra mobs basura con nombre) |
entity.elite | tabla o nil | Poblado solo cuando is_elite = true. Contiene level, name, health, max_health, health_multiplier, damage_multiplier, is_custom_boss, además de elite:remove() |
context.zones
Esta es la API de zones de FreeMinecraftModels/MagmaCore. Consulta context.zones para la referencia completa. Los poderes de jefe de EliteMobs usan una tabla context.zones distinta con definiciones de zona nativas de EliteMobs; consulta EliteMobs Zones & Targeting.
context.scheduler
La API de scheduler documentada aquí es el planificador de MagmaCore usado por los scripts de FreeMinecraftModels y los scripts de NPC de EliteMobs. Los nombres al estilo de EliteMobs (run_after, run_every y cancel_task) son alias sobre el planificador compartido, así que cualquiera de los dos estilos funciona. Los poderes de jefe exponen los mismos alias a través de su context específico de jefe. Consulta context.scheduler para la referencia completa de FMM.
context.state
La API de state es compartida por los scripts de FreeMinecraftModels, los poderes de jefe de EliteMobs y los scripts de NPC de EliteMobs. Consulta context.state para la referencia completa.
context.log
La API de logging documentada aquí es el logger de FreeMinecraftModels/MagmaCore (info, warn, error). Los scripts de NPC de EliteMobs usan el mismo logger; los poderes de jefe de EliteMobs exponen info, warn y debug. Consulta context.log para la referencia completa.
context.cooldowns
La API de cooldowns documentada aquí es el orden compartido de MagmaCore/FMM usado por los scripts de FreeMinecraftModels y los scripts de NPC de EliteMobs: check_local(key?, duration). Los poderes de jefe de EliteMobs usan el mismo orden de argumentos con almacenes de respaldo específicos de jefe. Consulta context.cooldowns para la referencia completa.
| Método | Notas |
|---|---|
local_ready(key?) | Comprueba si un cooldown local está listo. |
local_remaining(key?) | Devuelve los ticks restantes del cooldown local, o 0. |
check_local(key?, duration) | Comprueba e inicia un cooldown local de forma atómica. |
set_local(duration, key?) | Establece un cooldown local sin comprobarlo. |
global_ready() | Comprueba el cooldown global compartido del propietario del script. |
set_global(duration) | Establece el cooldown global compartido del propietario del script. |
Usa context.cooldowns:check_local("my_key", 40) para los cooldowns normales de acciones de prop o de ítem.
Modelo de Ejecución
Un Runtime por Instancia de Script
Cada entidad prop que tiene scripts adjuntos obtiene su propia instancia de runtime Lua independiente. Cuando el prop aparece, FMM carga el código fuente Lua, lo evalúa en un entorno sandbox fresco y almacena la tabla devuelta. Cuando se elimina el prop, el runtime se cierra.
Para scripts de objeto, se crea un runtime por par (jugador, itemId). Cuando un jugador equipa un objeto personalizado, FMM crea una instancia de script para ese jugador y tipo de objeto. Cuando el objeto se desequipa, el runtime se cierra.
Esto significa:
- Las variables locales declaradas en el ámbito de archivo son privadas para esa instancia de script.
context.stateestá completamente aislado entre instancias, incluso si comparten el mismo archivo de script.
Propiedad de Tareas Programadas
Todas las tareas creadas a través de context.scheduler son propiedad del runtime que las creó. Cuando se elimina un prop:
- El runtime se cierra.
- Cada tarea propia -- tanto de una sola vez como recurrente -- se cancela automáticamente.
- Todas las observaciones de zona se limpian.
Alcance de los Cooldowns
El motor de scripting compartido expone helpers de cooldown local (local_ready, local_remaining, check_local, set_local) y helpers de cooldown global (global_ready, set_global). FMM define el alcance de esos almacenes de la siguiente forma:
| Tipo de script | Alcance del store local | Alcance del store global |
|---|---|---|
| Script de prop | Por ScriptInstance (prop + archivo de script) | Por PropEntity (compartido entre todos los scripts vinculados a ese prop) |
| Script de objeto | Por triple (player, itemId, scriptFile) — persiste a través de reequipos aunque la instancia de script se derribe cada vez que el objeto sale de una ranura activa | Por jugador (compartido entre todos los scripts de objeto FMM que ese jugador ejecuta) |
Como los scripts de objeto se derriban y reconstruyen en cada ciclo de equip/unequip, los cooldowns de objeto se guardan en un mapa estático con clave por UUID de jugador en lugar de vivir en el ScriptInstance. Por eso un cooldown de objeto sigue aplicándose después de sacar el objeto del hotbar y volver a meterlo.
Esa persistencia se limita al runtime actual de FMM. /fmm reload, deshabilitar el plugin y reiniciar el servidor limpian tanto los almacenes de cooldown de objeto como los almacenes de cooldown global de props mientras los gestores de scripts se apagan.
Presupuesto de Ejecución
Cada invocación de hook, cada callback programado y la propia evaluación inicial del archivo de script se ejecutan bajo un presupuesto de ejecución estricto. El presupuesto se aplica dentro de la VM de Lua, así que actúa mientras tu código sigue ejecutándose en lugar de limitarse a mirar el reloj después.
| Límite | Valor |
|---|---|
| Tiempo de CPU del hilo actual | 50 milisegundos |
| Instrucciones de Lua ejecutadas | 250,000 |
El límite que se alcance primero aborta la llamada con un error de Lua y deshabilita la instancia del script. Los mensajes son:
Lua instruction budget exceeded (250000 instruction limit)
Lua CPU-time budget exceeded (50ms current-thread CPU limit)
Como la comprobación ocurre por instrucción, un while true do end no puede congelar el servidor.
La mitad temporal del presupuesto se mide como tiempo de CPU del hilo actual, no como tiempo de reloj, así que a un script no se le cobra el tiempo en el que el hilo del servidor estuvo fuera de planificación. En una JVM donde la medición de tiempo de CPU del hilo actual no esté disponible, MagmaCore recae en un límite deliberadamente más generoso de 250 milisegundos de tiempo transcurrido (Lua elapsed-time fallback budget exceeded (250ms fallback; current-thread CPU time unavailable)) manteniendo el mismo techo de 250.000 instrucciones, de modo que los scripts que no terminan siguen estando acotados en cualquier caso.
Las llamadas anidadas comparten un único presupuesto: si un hook invoca un callback que invoca otro, toda la cadena se mide como una única asignación de 50 ms de CPU / 250.000 instrucciones, no una asignación para cada uno.
Durante la evaluación inicial de un archivo de script todavía no existe ninguna instancia, así que la definición se rechaza y nunca se registra, en lugar de deshabilitarse.
Para mantenerse dentro del presupuesto:
- Evita bucles sin límite dentro de hooks.
- Mantén los manejadores
on_game_tickligeros -- se ejecutan en cada tick. - Usa
context.scheduler:run_repeating(...)para repartir el trabajo entre ticks.
Referencia Completa de Hooks
Esta tabla lista todos los hooks disponibles tanto en scripts de prop como de objeto.
La columna context.event describe la familia de eventos de Bukkit subyacente. El envoltorio de eventos de Lua de FMM sigue exponiendo únicamente event.player, event.is_cancelled, event.cancel() y event.uncancel() cuando corresponde.
Hooks de Prop Activos (7)
| Hook | Se dispara cuando | context.event |
|---|---|---|
on_spawn | El prop aparece en el mundo | nil |
on_game_tick | Cada tick del servidor (50ms) | nil |
on_destroy | El prop es eliminado | nil |
on_left_click | El jugador hace clic izquierdo en el prop | evento de daño |
on_right_click | El jugador hace clic derecho en el prop | evento de interacción |
on_zone_enter | El jugador entra en una zona observada | actor jugador de zona (context.player / context.event.player; no cancelable) |
on_zone_leave | El jugador sale de una zona observada | actor jugador de zona (context.player / context.event.player; no cancelable) |
El validador de scripts actual acepta on_projectile_hit para los scripts de prop, pero el runtime actual todavía no despacha impactos de proyectil a los scripts de prop. Usa el on_projectile_hit de ítem para comportamientos de proyectil ligados a un ítem con script, o la API de Bukkit ModeledEntityHitByProjectileEvent para el manejo de proyectiles contra entidades modeladas desde el lado del plugin.
Hooks de Objeto (22)
| Hook | Categoría | Se dispara cuando | context.event |
|---|---|---|---|
on_attack_entity | Combate | El jugador ataca una entidad | evento de daño |
on_kill_entity | Combate | El jugador mata una entidad | evento de muerte |
on_take_damage | Combate | El jugador recibe daño | evento de daño |
on_shield_block | Combate | El jugador bloquea con escudo | evento de daño |
on_shoot_bow | Combate | El jugador dispara un arco | evento de disparo de arco |
on_projectile_hit | Combate | El proyectil del jugador impacta | evento de impacto de proyectil |
on_projectile_launch | Combate | El jugador lanza un proyectil | evento de lanzamiento |
on_right_click | Interacción | El jugador hace clic derecho | evento de interacción |
on_left_click | Interacción | El jugador hace clic izquierdo | evento de interacción |
on_shift_right_click | Interacción | El jugador hace shift+clic derecho | evento de interacción |
on_shift_left_click | Interacción | El jugador hace shift+clic izquierdo | evento de interacción |
on_interact_entity | Interacción | El jugador hace clic derecho en una entidad | evento de interacción con entidad |
on_equip | Equipamiento | El objeto entra en ranura activa | nil |
on_unequip | Equipamiento | El objeto sale de ranura activa | nil |
on_swap_hands | Equipamiento | Intercambio entre mano principal/secundaria | evento de swap |
on_drop | Equipamiento | El jugador suelta el objeto | evento de drop |
on_break_block | Utilidad | El jugador rompe un bloque | evento de rotura de bloque |
on_consume | Utilidad | El jugador consume el objeto | evento de consumo |
on_item_damage | Utilidad | El objeto recibe daño de durabilidad | evento de daño de objeto |
on_fish | Utilidad | El jugador usa caña de pescar | evento de pesca |
on_death | Utilidad | El jugador muere mientras está equipado | evento de muerte |
on_game_tick | Ciclo de vida | Cada tick mientras está equipado | nil |
Siguientes Pasos
- Ejemplos y Patrones -- scripts completos y funcionales para props e ítems con recorridos guiados
- Solución de Problemas -- problemas comunes, consejos de depuración y una checklist de QC
- Primeros Pasos -- estructura de archivos, hooks, recorrido del primer script