Pular para o conteúdo principal

API do FreeMinecraftModels e Guia do Desenvolvedor

O FreeMinecraftModels é tanto um plugin independente quanto uma superfície de API para outros plugins.

Repositório 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>

Dependência

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

Use como compileOnly/provided. Não faça shade do plugin dentro do seu próprio jar.

Pontos de Entrada Principais

  • ModeledEntityManager.modelExists(String)
  • ModeledEntityManager.reload()
  • ModeledEntityManager.getAllEntities()
  • ModeledEntityManager.getDynamicEntities()
  • ModeledEntityManager.propEntities()
  • DisguiseAPI — disfarça / retira disfarce de jogadores como modelos carregados
  • LocationAPI — registra detectores de dungeon e provedores de proteção (alimenta os predicados Lua em.location.*)
  • ScriptedItemAPI — marca ItemStacks de terceiros com metadados de item programável do FMM

ModeledEntityManager.getAllEntities(), getDynamicEntities() e propEntities() retornam cópias de um instante no tempo. Modificar o conjunto ou mapa retornado não altera os registros vivos do FMM. Use modelExists(String) para uma verificação de existência, em vez de reter e copiar repetidamente um registro completo.

Tipos Principais de Runtime

  • ModeledEntity
  • StaticEntity
  • DynamicEntity
  • PropEntity

Criando 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);

Todos os caminhos de criação retornam null se o ID do modelo solicitado não estiver carregado.

PropEntity.spawnPropEntity retorna null adicionalmente quando um prop desse mesmo modelo já está carregado no bloco alvo — a duplicata é recusada em vez de empilhada, e um aviso [FMM Props] Prevented duplicate prop spawn ... é registrado. Sempre verifique o retorno contra null; um retorno não nulo é a única confirmação de que o prop foi realmente criado.

createWithInvisibility é uma variante que aplica uma poção de invisibilidade em vez de esconder a entidade dos clientes. Isso mantém a entidade rastreada no lado do cliente, necessário para direção de veículos (usado internamente por /fmm mount).

Métodos Úteis de Runtime

  • ModeledEntity#setDisplayName(String) -- silenciosamente não faz nada a menos que o modelo contenha um bone tag_ (veja o aviso abaixo)
  • ModeledEntity#setDisplayNameVisible(boolean) -- mesma exigência
  • ModeledEntity#setLeftClickCallback(...)
  • ModeledEntity#setRightClickCallback(...)
  • ModeledEntity#setHitboxContactCallback(...)
  • ModeledEntity#setModeledEntityHitByProjectileCallback(...)
  • ModeledEntity#playAnimation(String, boolean blend, boolean loop) -- retorna false quando o nome não corresponde nem a um estado embutido nem a uma animação do modelo. blend enfileira em vez de fazer cross-fade; loop só se aplica a animações personalizadas. Veja Animações
  • ModeledEntity#stopCurrentAnimations()
  • ModeledEntity#hasAnimation(String)
  • ModeledEntity#damage(double) / damage(Entity damager, double) / damage(Entity damager) / damage(Projectile) -- roteados pelo DamageableComponent da entidade
  • ModeledEntity#attack(LivingEntity) / attack(LivingEntity, double damage)
  • ModeledEntity#teleport(Location, boolean teleportUnderlyingEntity)
  • ModeledEntity#setUnderlyingEntity(Entity) / ModeledEntity.getModeledEntity(Entity) -- busca reversa estática de uma entidade Bukkit para o modelo anexado a ela, ou null
  • ModeledEntity#showUnderlyingEntity(Player) / hideUnderlyingEntity(Player) -- visibilidade por jogador da entidade vanilla de suporte
  • ModeledEntity#getEntityID() -- retorna a string do ID do modelo
  • ModeledEntity#getModelInstanceId() -- UUID por instância, estável durante toda a vida do modelo
  • ModeledEntity#isRemoved() / isDying() -- flags de ciclo de vida
  • ModeledEntity#getLocation() -- retorna o Location atual
  • ModeledEntity#getSpawnLocation() -- retorna o Location em que o modelo foi criado
  • ModeledEntity#getWorld() -- retorna o World
  • ModeledEntity#getSkeleton() / getSkeletonBlueprint() / getMountPointManager() -- acesso à estrutura em runtime
  • ModeledEntity#getInteractionComponent() / getHitboxComponent() / getDamageableComponent() / getAnimationComponent() -- os objetos de componente por trás dos métodos de conveniência acima
  • ModeledEntity.getLoadedModeledEntities() -- conjunto estático e vivo de todas as entidades modeladas carregadas
  • ModeledEntity#getViewers() -- retorna o HashSet<UUID> de jogadores que podem ver a entidade
  • ModeledEntity#getNametagBones() -- retorna List<Bone> de bones de nametag (útil para colocar texto adicional)
  • ModeledEntity#getScaleModifier() / setScaleModifier(double)
  • ModeledEntity#removeWithDeathAnimation() -- remove com a animação de morte (se existir uma)
  • ModeledEntity#removeWithMinimizedAnimation() -- remove com uma animação de redução de escala
  • ModeledEntity#remove() -- remove imediatamente a entidade e todos os bones
  • ModeledEntity#setTintColor(Color) / getTintColor() -- aplica um tint persistente via o canal de tinta de armadura de couro. Flashes de dano sobrescrevem brevemente o tint e então retornam a ele. Passe null para limpar.
  • ModeledEntity#setViewDistanceOverride(int) / getEffectiveViewDistance() -- sobrescreve DefaultConfig.maxModelViewDistance para uma única entidade. Passe -1 para reverter ao padrão geral do plugin.
  • DynamicEntity#setSyncMovement(boolean)
  • DynamicEntity#isDamagesOnContact() / setDamagesOnContact(boolean) -- controla se a entidade causa dano em jogadores via contato com hitbox
  • DynamicEntity.isDynamicEntity(Entity) / DynamicEntity.getDynamicEntity(Entity) -- buscas estáticas a partir de uma entidade Bukkit
  • DynamicEntity#getBodyLocation() -- localização orientada pelo corpo, distinta de getLocation()
  • Bone#getBoneLocation()

Especificidades de PropEntity

  • PropEntity.isPropEntity(ArmorStand) / PropEntity.getPropEntityID(ArmorStand) -- identificam um prop a partir do armor stand que o sustenta
  • PropEntity.hasLoadedPropOnSameBlock(String entityID, Location) -- a verificação de duplicata que o spawnPropEntity executa internamente; chame-a antes se quiser ramificar em vez de verificar null
  • PropEntity.respawnPropEntityFromArmorStand(String entityID, ArmorStand) -- reconstrói um prop em torno de um armor stand que sobreviveu a um recarregamento de chunk
  • PropEntity.getPropEntities() -- mapa vivo dos props carregados, indexado pelo UUID do armor stand
  • PropEntity#setPersistent(boolean) -- alterna a persistência no armor stand de suporte
  • PropEntity#setCustomDataString(NamespacedKey, String) / getCustomDataString(NamespacedKey) -- leem/escrevem seus próprios valores de PDC no prop. É o mesmo armazenamento usado pelos auxiliares Lua set_persistent_data / get_persistent_data, sob o namespace fmm_lua_<key>
  • PropEntity#remove() / remove(boolean showRealBlocks) -- removem o modelo, mas deixam a entrada persistente
  • PropEntity#permanentlyRemove() -- remove o modelo e sua entrada persistente
  • PropEntity#setVoxelizeConfig(boolean voxelize, boolean solidify) / applySolidify() -- os equivalentes em runtime dos campos YML voxelize: / solidify:
  • PropEntity#showFakePropBlocksToPlayer(Player) / showRealBlocksToPlayer(Player) e as variantes ...ToAllPlayers() -- controlam os blocos de barreira apenas em pacotes que dão colisão do lado do cliente a um prop solidificado
Nametags precisam de um bone tag_ no modelo

setDisplayName e setDisplayNameVisible percorrem os bones de nametag do modelo, que existem apenas para bones cujo nome começa com tag_. Em um modelo sem esse bone, essa lista fica vazia, então ambas as chamadas têm sucesso e não fazem nada — sem exceção, sem linha de log.

Não há fallback. Uma DynamicEntity esconde dos clientes a entidade viva subjacente, então o nametag vanilla do mob também não aparece. O resultado líquido é um mob completamente sem nome, mesmo que seu plugin tenha definido o nome sem erro.

Se o seu plugin nomeia modelos (bosses, NPCs, qualquer coisa visível ao usuário), exija um bone tag_ nos modelos que você distribui, ou verifique getNametagBones().isEmpty() no momento do anexo e avise o autor do conteúdo. Veja Notas de Criação de Modelos.

Superfície de Eventos

Eventos de interação genéricos:

  • ModeledEntityLeftClickEvent
  • ModeledEntityRightClickEvent
  • ModeledEntityHitboxContactEvent
  • ModeledEntityHitByProjectileEvent

Todos os quatro são eventos Bukkit canceláveis; os caminhos de detecção internos do FMM os despacham na thread principal do servidor. Cancelar um deles impede o callback/comportamento padrão correspondente do FMM. As varreduras de contato com hitbox rodam a cada dois ticks do servidor; os eventos de clique ainda têm uma curta janela de deduplicação por jogador, para que os caminhos de interação por pacote e de raytrace OBB não disparem a mesma ação duas vezes.

Eventos de ciclo de vida:

  • FmmReloadedEvent -- dispara após o FMM terminar sua sequência de inicialização na inicialização e após cada /fmm reload. Sempre dispara na thread principal do servidor.

A superfície pública de interação é intencionalmente neutra quanto ao tipo de modelo. As antigas variantes StaticEntity*Event, DynamicEntity*Event e PropEntity*Event, junto com ResourcePackGenerationEvent, não fazem mais parte da API atual. Use os quatro eventos genéricos de entidade modelada acima e o FmmReloadedEvent.

Plugins consumidores que mantêm referências de longa duração a DynamicEntity ou PropEntity (EliteMobs, BetterStructures, etc.) devem lidar com este evento recriando seus anexos de modelo nas entidades subjacentes sobreviventes. Sem isso, essas entidades ficam invisíveis após um reload porque o FMM derrubou as display entities durante onDisable enquanto a referência do consumidor agora está obsoleta.

@EventHandler
public void onFmmReloaded(FmmReloadedEvent event) {
for (MyTrackedEntity tracked : myEntities) {
if (tracked.bukkitEntity != null && tracked.bukkitEntity.isValid()) {
tracked.fmmModel = DynamicEntity.create("my_model", tracked.bukkitEntity);
}
}
}

ModeledEntityHitByProjectileEvent e Detecção de Projéteis OBB

O FMM usa detecção de hit OBB (oriented bounding box) para projéteis contra entidades modeladas. Quando um projétil intersecta o hitbox OBB de uma entidade modelada, o FMM dispara um ModeledEntityHitByProjectileEvent. Este é um evento Bukkit cancelável padrão.

Detalhes principais:

  • A detecção varre todo o segmento de movimento do projétil desde o tick anterior, então flechas rápidas não podem atravessar um modelo fino entre amostras
  • Candidatos nesse segmento são resolvidos do mais próximo ao mais distante, independentemente da ordem de iteração do registro de modelos
  • Um projétil sem perfuração é roteado para um único alvo modelado. Uma flecha com Piercing pode atingir nível de perfuração + 1 alvos modelados distintos, na ordem de trajetória, sem disparo duplo quando tanto o OBB quanto as hitboxes vanilla de suporte a observam
  • O handler padrão de entidades dinâmicas encaminha o impacto para a entidade viva subjacente como um evento real de dano por projétil, usando a velocidade do projétil no momento do impacto. Isso preserva a causa do projétil, o tratamento por plugins de combate e a atribuição ao atirador
  • Cancelar o evento impede o callback/dano padrão do FMM, mas a colisão ainda consome a cota de alvos modelados daquele projétil. Um acerto sem perfuração que foi cancelado, portanto, ainda consome o projétil
@EventHandler
public void onProjectileHitModel(ModeledEntityHitByProjectileEvent event) {
ModeledEntity target = event.getModeledEntity();
Projectile projectile = event.getProjectile();
// Cancel to prevent damage
event.setCancelled(true);
}

Utilitários de Item e Modelo

ModelItemFactory

Classe factory para criar ItemStacks relacionados a modelos programaticamente.

// Create a prop placement item (uses "model_id" PDC key)
ItemStack placementItem = ModelItemFactory.createModelItem("lamp_post", Material.STICK);

// Create a custom item from config (uses "fmm_item_id" PDC key)
PropScriptConfigFields config = ItemScriptManager.getItemDefinitions().get("magic_sword");
ItemStack customItem = ModelItemFactory.createCustomItem("magic_sword", config);
  • createModelItem(String modelId, Material material) -- cria um item de colocação para props. Em 1.21.4+, aplica automaticamente renderização de display model se um JSON de display existir.
  • createCustomItem(String itemId, PropScriptConfigFields config) -- cria um item customizado com nome, lore, encantamentos e display model a partir da config unificada.
  • formatModelName(String modelId) -- utilitário que converte um ID de modelo como 01_em_flame_sword em Flame Sword.

DisplayModelRegistry

Registro simples que rastreia quais modelos têm um JSON de display disponível.

// Check if a model has a display model JSON registered
boolean has3D = DisplayModelRegistry.hasDisplayModel("magic_sword");
  • register(String modelId) -- registra um ID de modelo (chamado internamente durante o reload)
  • hasDisplayModel(String modelId) -- retorna true se um .json de display model existir para este modelo
  • getRegisteredModels() -- retorna um Set<String> imutável de todos os IDs de modelo que têm display models registrados
  • shutdown() -- limpa todos os registros

ItemScriptManager

Gerencia o ciclo de vida de scripts Lua por jogador para itens customizados (modelos com material: definido em sua configuração YML).

// Get all registered custom item definitions
Map<String, PropScriptConfigFields> items = ItemScriptManager.getItemDefinitions();

// Get the active Lua script instance for a player + item
ScriptInstance instance = ItemScriptManager.getActiveScript(playerUUID, "magic_sword");

// Get all active scripts for a player
Map<String, ScriptInstance> scripts = ItemScriptManager.getActiveScripts(playerUUID);
  • scanForCustomItems(File modelsFolder) -- escaneia configurações YML de modelos para itens customizados
  • updateEquippedScripts(Player player) -- faz diff de itens equipados contra scripts em execução, disparando hooks de equip/unequip
  • removePlayer(Player player) -- encerra todos os scripts para um jogador (chame ao sair)
  • getItemDefinitions() -- retorna o mapa de ID de item para PropScriptConfigFields

ScriptedItemAPI

API pública para plugins externos integrarem com o sistema de itens programáveis do FMM. Isso permite que outros plugins marquem seus próprios ItemStacks com dados de item programável do FMM (tag PDC + item model) para que os hooks de script Lua do FMM disparem para esses itens, sem o FMM sobrescrever o nome, lore ou encantamentos do item.

// Check if a scripted item definition exists
boolean exists = ScriptedItemAPI.isValidItemId("flame_blade");

// Apply FMM scripted item data to an existing ItemStack
// This sets:
// - The fmm_item_id PDC tag (so FMM's script system recognizes the item)
// - The item model (1.21.4+) from FMM's display model registry
// Does NOT modify name, lore, enchantments, or any other item properties.
boolean success = ScriptedItemAPI.applyScriptedItemData(itemStack, "flame_blade");

// Get the config for a scripted item
PropScriptConfigFields config = ScriptedItemAPI.getItemConfig("flame_blade");
  • isValidItemId(String itemId) -- retorna true se o ID do item está registrado nas definições de item do FMM
  • applyScriptedItemData(ItemStack itemStack, String itemId) -- carimba tag PDC e item model em um ItemStack existente. Retorna true em sucesso, false se o ID do item é inválido ou o ItemStack não tem meta. Nota para arco/besta: se o itemId dado não tem um display model mas itemId + "_idle" tem (ou seja, o item tem modelos de estado de arco/besta), o método usa automaticamente o modelo _idle como display model
  • getItemConfig(String itemId) -- retorna o PropScriptConfigFields para o ID de item dado, ou null se não encontrado
Integração com EliteMobs

O EliteMobs usa esta API internamente via o campo de config scriptedItem. Quando um item customizado do EliteMobs define scriptedItem: flame_blade, o EliteMobs constrói seu item normalmente (nome, lore, encantamentos, nível) e então chama ScriptedItemAPI.applyScriptedItemData() para adicionar o modelo e comportamento de script do FMM por cima.

DisguiseAPI

Ponto de entrada público para o recurso de disfarce de jogadores. Plugins de terceiros devem chamar esta classe em vez do DisguiseManager interno para que refatorações internas permaneçam seguras.

import com.magmaguy.freeminecraftmodels.api.DisguiseAPI;

// Disguise a player as a loaded model. Replaces any existing disguise cleanly.
boolean ok = DisguiseAPI.disguise(player, "dragon");

// Undisguise (returns true if a disguise was removed).
DisguiseAPI.undisguise(player);

// Query state.
boolean disguised = DisguiseAPI.isDisguised(player);
String modelID = DisguiseAPI.getDisguiseModelID(player); // null if not disguised

// Snapshot of all currently disguised players.
Collection<Player> all = DisguiseAPI.getDisguisedPlayers();
  • disguise(Player, String modelID) -- retorna false se o ID do modelo não estiver carregado
  • undisguise(Player) -- retorna true se um disfarce foi removido
  • isDisguised(Player) -- verificação booleana rápida
  • getDisguiseModelID(Player) -- retorna o ID do modelo ativo ou null
  • getDisguisedPlayers() -- snapshot imutável de jogadores disfarçados

Jogadores disfarçados ficam invisíveis para os outros e assim permanecem até que o disfarce seja removido — baldes de leite, limpezas de efeito por beacon e interações similares não quebram a invisibilidade.

LocationAPI

API pública para plugins contribuírem com detecção de dungeon e verificações de proteção de região. Os predicados registrados alimentam as verificações Lua em.location.is_in_dungeon e em.location.is_protected do FMM (usadas por scripts pré-feitos como pickupable.lua e storage_double.lua).

Plugins passam um Predicate<Location> puro para que nenhum tipo FMM com shade atravesse classloaders de plugins.

import com.magmaguy.freeminecraftmodels.api.LocationAPI;

// On your plugin's enable, after WorldGuard/EliteMobs/etc. are available.
LocationAPI.registerDungeonLocator("EliteMobs",
location -> EliteMobs.isInsideDungeon(location));

LocationAPI.registerProtectionProvider("WorldGuard",
location -> WorldGuardBridge.isProtected(location));
  • registerDungeonLocator(String providerName, Predicate<Location> predicate) — qualquer predicado registrado retornando true marca a localização como "em dungeon"
  • registerProtectionProvider(String providerName, Predicate<Location> predicate) — qualquer predicado registrado retornando true marca a localização como protegida

Operadores podem verificar o registro com /fmm location, que reporta a contagem ao vivo de provedores e testa ambos os predicados contra a localização atual.

Provedores de proteção e colocação de props

Os mesmos provedores de proteção também alimentam a verificação de colocação de props preventPropPlacementInProtectedRegions, mas essa verificação chama canBuild(player, location) em vez do isProtected(location) baseado apenas em localização. A distinção importa:

ProvedorComportamento de canBuild
Adaptador integrado do WorldGuardRespeita o bypass do próprio WorldGuard e depois delega ao testBuild do WorldGuard — assim, membros e donos da região podem construir normalmente
Adaptador integrado do GriefPreventionNenhum claim na localização significa permitido; dentro de um claim, delega à própria permissão de construção do GriefPrevention para aquele jogador
Provedor registrado via LocationAPI.registerProtectionProviderRecai em !isProtected(location)apenas por localização, bloqueia todo mundo numa localização que o seu predicado considere protegida

Esse fallback é intencional e conservador: um Predicate<Location> não consegue expressar permissão específica de jogador, então o FMM não vai inventar uma. Se você quer comportamento genuinamente ciente do jogador para o seu próprio sistema de regiões, implemente diretamente o RegionProtectionProvider do MagmaCore e sobrescreva canBuild, depois registre-o com LocationQueryRegistry.registerProtectionProvider em vez de passar pelo wrapper de conveniência com predicado.

Mais dois comportamentos que vale conhecer:

  • Falhas de adaptador falham de forma fechada. Se um provedor lançar erro durante uma consulta de construção, a colocação é recusada e um aviso nomeando o provedor é registrado. Nunca se degrada silenciosamente para "permitido".
  • Todo provedor registrado precisa concordar. O primeiro provedor que disser não vence; provedores de propriedade registrados via LocationOwnership continuam sendo apenas por localização e bloqueiam todo mundo.

PropScriptConfigFields

Classe de configuração unificada para arquivos YML de config de modelo. Usada tanto por scripts de prop quanto por itens customizados.

# Example: torch_01.yml
isEnabled: true
scripts:
- torch_glow.lua
material: STICK # If set, model becomes a custom item
name: "&eMagic Torch" # Custom display name (optional)
lore: # Custom lore lines (optional)
- "&7Glows in the dark"
enchantments: # Enchantments (optional, format: NAME,LEVEL)
- "FIRE_ASPECT,1"

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

Scripting Lua

O FreeMinecraftModels suporta scripts Lua tanto para props quanto para itens customizados através do motor de scripting MagmaCore 2.0. Arquivos de script são colocados em plugins/FreeMinecraftModels/scripts/ e são vinculados a modelos via uma config YML irmã ao lado do arquivo do modelo. O arquivo de script no disco precisa terminar em .lua; entradas de config podem incluir a extensão ou omiti-la.

Props vinculam cada script listado em scripts: como instâncias independentes. Itens customizados atualmente vinculam apenas o primeiro script válido da lista para cada par jogador/item.

Hooks de Script de Prop

HookGatilho
on_spawnO prop é spawnado no mundo
on_game_tickA cada tick enquanto o prop estiver vivo
on_zone_enterUm jogador entra em uma zona monitorada criada por script
on_zone_leaveUm jogador sai de uma zona monitorada criada por script
on_destroyO prop é removido
on_left_clickO jogador clica com botão esquerdo no prop
on_right_clickO jogador clica com botão direito no prop
on_projectile_hitReservado: aceito pela validação, mas não despachado para scripts de prop no runtime atual

Hooks de Script de Item

Itens customizados (modelos com material: definido) suportam 22 hooks Lua:

HookGatilho
on_equipO item entra em um slot de equipamento rastreado
on_unequipO item sai de um slot de equipamento rastreado
on_game_tickA cada tick enquanto o item estiver equipado
on_attack_entityO jogador ataca uma entidade segurando o item
on_kill_entityO jogador mata uma entidade segurando o item
on_take_damageO jogador sofre dano enquanto o item está equipado
on_shield_blockO jogador bloqueia com um escudo
on_shoot_bowO jogador atira com um arco
on_projectile_hitUm projétil disparado pelo jogador atinge algo
on_projectile_launchO jogador lança um projétil
on_right_clickO jogador clica com botão direito com o item
on_left_clickO jogador clica com botão esquerdo com o item
on_shift_right_clickO jogador shift-clica com botão direito com o item
on_shift_left_clickO jogador shift-clica com botão esquerdo com o item
on_interact_entityO jogador clica com botão direito em uma entidade com o item
on_swap_handsO jogador troca o item entre as mãos
on_dropO jogador derruba o item
on_break_blockO jogador quebra um bloco segurando o item
on_consumeO jogador consome o item
on_item_damageO item sofre dano de durabilidade
on_fishO jogador usa uma vara de pesca
on_deathO jogador morre com o item equipado

Scripts de item recebem context.item (com o ID do item e info do jogador) em vez de context.prop.

Tabela de Contexto do Script de Prop

Scripts de prop recebem uma tabela context. Aqui está um resumo das APIs principais -- veja API Lua de Prop para detalhes completos.

context.prop:

  • model_id -- o nome do modelo blueprint
  • current_location -- a localização atual do prop
  • play_animation(name, blend, loop) -- toca a animação nomeada (blend e loop padrão para true)
  • stop_animation() -- para todas as animações atuais
  • hurt_visual() -- toca o visual de dano (flash vermelho) no prop
  • pickup() -- enfileira a remoção do prop e o drop do seu item de colocação
  • mount(player) -- enfileira uma tentativa de montaria; um retorno true significa que o jogador e o gerenciador de montarias eram válidos, não que um assento tenha sido de fato atribuído
  • dismount(player) -- enfileira uma verificação de desmonte; um retorno true significa que o jogador e o gerenciador de montarias eram válidos
  • get_passengers() -- retorna uma lista de jogadores atualmente montados no prop
  • spawn_elitemobs_boss(filename, x, y, z) -- spawna um chefe EliteMobs em coordenadas absolutas no mundo atual do prop

context.event:

  • Disponível nos hooks de prop on_left_click, on_right_click, on_zone_enter e on_zone_leave, além dos hooks de item causados por um jogador
  • cancel(), uncancel(), is_cancelled quando o hook subjacente é cancelável
  • player -- o jogador que disparou o evento

context.world:

  • spawn_entity(entity_type, x, y, z) -- spawna uma entidade vanilla, ou retorna nil se o tipo de entidade for inválido
  • set_block_at(x, y, z, material) -- enfileira uma mudança de bloco se o material for válido; chunks descarregados são pulados
  • Além de partículas, sons, consultas de blocos, raios e buscas de entidades próximas

context.cooldowns:

  • check_local(key, ticks) -- verifica e inicia um cooldown por script
  • global_ready() / set_global(ticks) -- cooldown compartilhado do prop ou do jogador dono

Objetos de jogador (de context.player ou context.event.player):

  • get_held_item() -- retorna o item que o jogador está segurando; type é o nome do material Bukkit em maiúsculas
  • consume_held_item() -- remove um do item segurado
  • has_item(material) -- verifica se o jogador tem um item
  • send_message(text) -- envia uma mensagem de chat ao jogador
  • game_mode -- o modo de jogo atual do jogador

Exemplo de Script de Prop

return {
api_version = 1,

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

on_right_click = function(context)
if context.cooldowns:check_local("activate", 40) then
context.prop:play_animation("activate", false, false)
end
end
}

Exemplo de Script de Item

return {
api_version = 1,

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

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

on_unequip = function(context)
context.player:send_message("&7Flame Blade sheathed.")
end
}

Notas

  • O FreeMinecraftModels é uma dependência de plugin instalado, não uma biblioteca embarcável.
  • Se seu plugin precisa de modelos recém-importados, chame ModeledEntityManager.reload() em vez de tentar reconstruir o estado do FreeMinecraftModels sozinho.
  • ModeledEntityManager.reload() executa um ciclo completo de reload do plugin (onDisable / onLoad / onEnable). Chame-o na thread principal do servidor.
  • Todos os plugins no ecossistema Nightbreak agora dependem do MagmaCore 2.2.0-SNAPSHOT, que inclui o motor de scripting Lua compartilhado usado por scripts de prop do FreeMinecraftModels e poderes Lua do EliteMobs, mais o LocationQueryRegistry e WorldFolderResolver compartilhados.
  • O FreeMinecraftModels declara WorldGuard, WorldEdit, GriefPrevention, Vault, floodgate e Geyser-Spigot como softdepend. Nenhum é obrigatório para iniciar o plugin, mas eles desbloqueiam recursos específicos: WorldGuard/WorldEdit/GriefPrevention alimentam a LocationAPI e a verificação de colocação de props ciente do jogador, o Vault habilita a loja de mobília, e floodgate/Geyser-Spigot habilitam o backend Bedrock por modelo.