Saltar al contenido principal

API y Guía para Desarrolladores de FreeMinecraftModels

FreeMinecraftModels es tanto un plugin independiente como una superficie de API para otros plugins.

Repositorio Maven

<repository>
<id>magmaguy-repo-releases</id>
<name>MagmaGuy's Repository</name>
<url>https://repo.magmaguy.com/releases</url>
</repository>
<repository>
<id>magmaguy-repo-snapshots</id>
<name>MagmaGuy's Snapshot Repository</name>
<url>https://repo.magmaguy.com/snapshots</url>
</repository>

Dependencia

<dependency>
<groupId>com.magmaguy</groupId>
<artifactId>FreeMinecraftModels</artifactId>
<version>LATEST.VERSION.HERE</version>
<scope>provided</scope>
</dependency>

Úsalo como compileOnly/provided. No empaquetes el plugin dentro de tu propio jar.

Puntos de Entrada Principales

  • ModeledEntityManager.modelExists(String)
  • ModeledEntityManager.reload()
  • ModeledEntityManager.getAllEntities()
  • ModeledEntityManager.getDynamicEntities()
  • ModeledEntityManager.propEntities()

Tipos Principales del Runtime

  • ModeledEntity
  • StaticEntity
  • DynamicEntity
  • PropEntity

Crear Entidades

StaticEntity preview = StaticEntity.create("example_model", location);
DynamicEntity mobModel = DynamicEntity.create("example_model", livingEntity);
DynamicEntity mount = DynamicEntity.createWithInvisibility("example_model", livingEntity);
PropEntity prop = PropEntity.spawnPropEntity("example_model", location);

Todas las rutas de creación devuelven null si el ID de modelo solicitado no está cargado.

createWithInvisibility es una variante que aplica una poción de invisibilidad en lugar de ocultar la entidad de los clientes. Esto mantiene la entidad rastreada del lado del cliente, lo cual es necesario para la dirección de vehículos (usado internamente por /fmm mount).

Métodos Útiles del Runtime

  • ModeledEntity#setDisplayName(String)
  • ModeledEntity#setDisplayNameVisible(boolean)
  • ModeledEntity#setLeftClickCallback(...)
  • ModeledEntity#setRightClickCallback(...)
  • ModeledEntity#setHitboxContactCallback(...)
  • ModeledEntity#setModeledEntityHitByProjectileCallback(...)
  • ModeledEntity#playAnimation(String, boolean, boolean)
  • ModeledEntity#stopCurrentAnimations()
  • ModeledEntity#hasAnimation(String)
  • DynamicEntity#setSyncMovement(boolean)
  • Bone#getBoneLocation()

Superficie de Eventos

Eventos de interacción genéricos:

  • ModeledEntityLeftClickEvent
  • ModeledEntityRightClickEvent
  • ModeledEntityHitboxContactEvent
  • ModeledEntityHitByProjectileEvent

También existen variantes tipadas para StaticEntity, DynamicEntity y PropEntity.

ModeledEntityHitByProjectileEvent y Detección de Proyectiles con OBB

FMM utiliza detección de impacto OBB (caja delimitadora orientada) para proyectiles contra entidades modeladas. Cuando un proyectil intersecta la hitbox OBB de una entidad modelada, FMM dispara un ModeledEntityHitByProjectileEvent. Este es un evento Bukkit cancelable estándar.

Detalles clave:

  • El daño de flechas se calcula con soporte para el bonus del encantamiento POWER
  • El encantamiento PIERCING es respetado -- las flechas pueden atravesar hacia objetivos adicionales
  • Cancela el evento para prevenir el daño y bloquear el impacto completamente
@EventHandler
public void onProjectileHitModel(ModeledEntityHitByProjectileEvent event) {
ModeledEntity target = event.getModeledEntity();
Projectile projectile = event.getProjectile();
// Cancelar para prevenir daño
event.setCancelled(true);
}

Utilidades de Ítems y Modelos

ModelItemFactory

Clase factory para crear ItemStacks relacionados con modelos programáticamente.

// Crear un ítem de colocación de prop (usa clave PDC "model_id")
ItemStack placementItem = ModelItemFactory.createModelItem("lamp_post", Material.STICK);

// Crear un ítem personalizado desde configuración (usa clave PDC "fmm_item_id")
PropScriptConfigFields config = ItemScriptManager.getItemDefinitions().get("magic_sword");
ItemStack customItem = ModelItemFactory.createCustomItem("magic_sword", config);
  • createModelItem(String modelId, Material material) -- crea un ítem de colocación para props. En 1.21.4+, aplica automáticamente el renderizado de display model si existe un JSON de display.
  • createCustomItem(String itemId, PropScriptConfigFields config) -- crea un ítem personalizado con nombre, lore, encantamientos y display model desde la configuración unificada.
  • formatModelName(String modelId) -- utilidad que convierte un ID de modelo como 01_em_flame_sword en Flame Sword.

DisplayModelRegistry

Registro simple que rastrea qué modelos tienen un JSON de display disponible.

// Verificar si un modelo tiene un JSON de display model registrado
boolean has3D = DisplayModelRegistry.hasDisplayModel("magic_sword");
  • register(String modelId) -- registra un ID de modelo (llamado internamente durante la recarga)
  • hasDisplayModel(String modelId) -- devuelve true si existe un .json de display model para este modelo
  • shutdown() -- limpia todos los registros

ItemScriptManager

Gestiona el ciclo de vida de scripts Lua por jugador para ítems personalizados (modelos con material: establecido en su configuración YML).

// Obtener todas las definiciones de ítems personalizados registradas
Map<String, PropScriptConfigFields> items = ItemScriptManager.getItemDefinitions();

// Obtener la instancia de script Lua activa para un jugador + ítem
ScriptInstance instance = ItemScriptManager.getActiveScript(playerUUID, "magic_sword");

// Obtener todos los scripts activos para un jugador
Map<String, ScriptInstance> scripts = ItemScriptManager.getActiveScripts(playerUUID);
  • scanForCustomItems(File modelsFolder) -- escanea las configuraciones YML de modelos en busca de ítems personalizados
  • updateEquippedScripts(Player player) -- compara los ítems equipados contra los scripts en ejecución, disparando hooks de equipar/desequipar
  • removePlayer(Player player) -- cierra todos los scripts para un jugador (llamar al desconectarse)
  • getItemDefinitions() -- devuelve el mapa de ID de ítem a PropScriptConfigFields

ScriptedItemAPI

API pública para que plugins externos se integren con el sistema de ítems con scripts de FMM. Esto permite a otros plugins marcar sus propios ItemStacks con datos de ítems con scripts de FMM (etiqueta PDC + modelo de ítem) para que los hooks de scripts Lua de FMM se activen para esos ítems, sin que FMM sobrescriba el nombre, lore o encantamientos del ítem.

// Verificar si existe una definición de ítem con script
boolean exists = ScriptedItemAPI.isValidItemId("flame_blade");

// Aplicar datos de ítem con script de FMM a un ItemStack existente
// Esto establece:
// - La etiqueta PDC fmm_item_id (para que el sistema de scripts de FMM reconozca el ítem)
// - El modelo de ítem (1.21.4+) del registro de display model de FMM
// NO modifica nombre, lore, encantamientos ni ninguna otra propiedad del ítem.
boolean success = ScriptedItemAPI.applyScriptedItemData(itemStack, "flame_blade");

// Obtener la configuración de un ítem con script
PropScriptConfigFields config = ScriptedItemAPI.getItemConfig("flame_blade");
  • isValidItemId(String itemId) -- devuelve true si el ID de ítem está registrado en las definiciones de ítems de FMM
  • applyScriptedItemData(ItemStack itemStack, String itemId) -- marca la etiqueta PDC y el modelo de ítem en un ItemStack existente. Devuelve true en caso de éxito, false si el ID de ítem es inválido o el ItemStack no tiene meta. Nota para arco/ballesta: si el itemId dado no tiene un display model pero itemId + "_idle" sí (es decir, el ítem tiene modelos de estado de arco/ballesta), el método usa automáticamente el modelo _idle como display model
  • getItemConfig(String itemId) -- devuelve el PropScriptConfigFields para el ID de ítem dado, o null si no se encuentra
Integración con EliteMobs

EliteMobs usa esta API internamente a través del campo de configuración scriptedItem. Cuando un ítem personalizado de EliteMobs establece scriptedItem: flame_blade, EliteMobs construye su ítem normalmente (nombre, lore, encantamientos, nivel) y luego llama a ScriptedItemAPI.applyScriptedItemData() para agregar el modelo y comportamiento de script de FMM encima.

PropScriptConfigFields

Clase de configuración unificada para archivos de configuración YML de modelos. Usada tanto por scripts de props como por ítems personalizados.

# Ejemplo: torch_01.yml
isEnabled: true
scripts:
- torch_glow.lua
material: STICK # Si se establece, el modelo se convierte en un ítem personalizado
name: "&eMagic Torch" # Nombre de visualización personalizado (opcional)
lore: # Líneas de lore personalizadas (opcional)
- "&7Glows in the dark"
enchantments: # Encantamientos (opcional, formato: NAME,LEVEL)
- "FIRE_ASPECT,1"

Métodos clave: isCustomItem(), getParsedMaterial(), getParsedEnchantments(), getScripts().

Scripting Lua

FreeMinecraftModels soporta scripts Lua tanto para props como para ítems personalizados a través del motor de scripting MagmaCore 2.0. Los archivos de script se colocan en plugins/FreeMinecraftModels/scripts/ y se vinculan a modelos mediante un archivo de configuración YML hermano al archivo del modelo.

Hooks de Scripts de Props

HookDisparador
on_spawnEl prop aparece en el mundo
on_game_tickCada tick mientras el prop esté activo
on_zone_enterUn jugador entra en la zona del prop
on_zone_leaveUn jugador sale de la zona del prop
on_destroyEl prop es eliminado
on_left_clickUn jugador hace clic izquierdo en el prop
on_right_clickUn jugador hace clic derecho en el prop
on_projectile_hitUn proyectil impacta en el prop

Hooks de Scripts de Ítems

Los ítems personalizados (modelos con material: establecido) soportan 22 hooks Lua:

HookDisparador
on_equipEl ítem entra en un slot de equipamiento rastreado
on_unequipEl ítem sale de un slot de equipamiento rastreado
on_game_tickCada tick mientras el ítem está equipado
on_attack_entityEl jugador ataca una entidad mientras sostiene el ítem
on_kill_entityEl jugador mata una entidad mientras sostiene el ítem
on_take_damageEl jugador recibe daño mientras el ítem está equipado
on_shield_blockEl jugador bloquea con un escudo
on_shoot_bowEl jugador dispara un arco
on_projectile_hitUn proyectil disparado por el jugador impacta algo
on_projectile_launchEl jugador lanza un proyectil
on_right_clickEl jugador hace clic derecho con el ítem
on_left_clickEl jugador hace clic izquierdo con el ítem
on_shift_right_clickEl jugador hace shift+clic derecho con el ítem
on_shift_left_clickEl jugador hace shift+clic izquierdo con el ítem
on_interact_entityEl jugador hace clic derecho en una entidad con el ítem
on_swap_handsEl jugador intercambia el ítem entre manos
on_dropEl jugador suelta el ítem
on_break_blockEl jugador rompe un bloque mientras sostiene el ítem
on_consumeEl jugador consume el ítem
on_item_damageEl ítem recibe daño de durabilidad
on_fishEl jugador usa una caña de pescar
on_deathEl jugador muere mientras el ítem está equipado

Los scripts de ítems reciben context.item (con el ID del ítem e información del jugador) en lugar de context.prop.

Tabla de Contexto de Scripts de Props

Los scripts de props reciben una tabla context. Aquí hay un resumen de las APIs principales -- consulta API Lua de Props e Ítems para detalles completos.

context.prop:

  • model_id -- el nombre del modelo blueprint
  • current_location -- la ubicación actual del prop
  • play_animation(name, blend, loop) -- reproduce la animación indicada (blend y loop por defecto en true)
  • stop_animation() -- detiene todas las animaciones actuales
  • hurt_visual() -- reproduce el visual de daño (destello rojo) en el prop
  • pickup() -- elimina el prop y suelta su ítem de colocación
  • mount(player) -- hace que un jugador monte el prop
  • dismount(player) -- desmonta a un jugador del prop
  • get_passengers() -- devuelve una lista de jugadores que actualmente montan el prop
  • spawn_elitemobs_boss(filename, x, y, z) -- genera un jefe de EliteMobs relativo al prop

context.event:

  • Disponible en on_left_click, on_right_click y on_projectile_hit
  • cancel(), uncancel(), is_cancelled
  • player -- el jugador que activó el evento

context.world:

  • spawn_entity(entity_type, location) -- genera una entidad vanilla
  • set_block_at(location, material) -- establece un bloque en el mundo
  • Además de partículas, sonidos, consultas de bloques, rayos y búsquedas de entidades cercanas

Objetos de jugador (de context.event.player):

  • get_held_item() -- devuelve el ítem que el jugador está sosteniendo
  • consume_held_item() -- elimina uno del ítem sostenido
  • has_item(material) -- verifica si el jugador tiene un ítem
  • send_message(text) -- envía un mensaje de chat al jugador
  • game_mode -- el modo de juego actual del jugador

Ejemplo de Script de Prop

function on_spawn(context)
context.prop.play_animation("idle", true, true)
end

function on_right_click(context)
context.prop.play_animation("activate", false, false)
end

Ejemplo de Script de Ítem

function on_equip(context)
context.event.player.send_message("&6You equipped the Flame Blade!")
end

function on_attack_entity(context)
-- Fire effect on hit
context.event.player.send_message("&cBurn!")
end

function on_unequip(context)
context.event.player.send_message("&7Flame Blade sheathed.")
end

Notas

  • FreeMinecraftModels es una dependencia de plugin instalado, no una biblioteca para incrustar.
  • Si tu plugin necesita modelos recién importados, llama a ModeledEntityManager.reload() en lugar de intentar reconstruir el estado de FreeMinecraftModels por tu cuenta.
  • Todos los plugins del ecosistema Nightbreak ahora dependen de MagmaCore 2.0.0-SNAPSHOT, que incluye el motor de scripting Lua compartido utilizado por los scripts de props de FreeMinecraftModels y los poderes Lua de EliteMobs.