FreeMinecraftModels API and Developer Guide
FreeMinecraftModels is both a standalone plugin and an API surface for other plugins.
Maven Repository
<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>
Dependency
<dependency>
<groupId>com.magmaguy</groupId>
<artifactId>FreeMinecraftModels</artifactId>
<version>LATEST.VERSION.HERE</version>
<scope>provided</scope>
</dependency>
Use it as compileOnly/provided. Do not shade the plugin into your own jar.
Core Entry Points
ModeledEntityManager.modelExists(String)ModeledEntityManager.reload()ModeledEntityManager.getAllEntities()ModeledEntityManager.getDynamicEntities()ModeledEntityManager.propEntities()
Core Runtime Types
ModeledEntityStaticEntityDynamicEntityPropEntity
Creating Entities
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);
All creation paths return null if the requested model ID is not loaded.
createWithInvisibility is a variant that applies an invisibility potion instead of hiding the entity from clients. This keeps the entity tracked client-side, which is needed for vehicle steering (used internally by /fmm mount).
Useful Runtime Methods
ModeledEntity#setDisplayName(String)ModeledEntity#setDisplayNameVisible(boolean)ModeledEntity#setLeftClickCallback(...)ModeledEntity#setRightClickCallback(...)ModeledEntity#setHitboxContactCallback(...)ModeledEntity#setModeledEntityHitByProjectileCallback(...)ModeledEntity#playAnimation(String, boolean, boolean)ModeledEntity#stopCurrentAnimations()ModeledEntity#hasAnimation(String)ModeledEntity#getEntityID()-- returns the model ID stringModeledEntity#getLocation()-- returns the currentLocationModeledEntity#getWorld()-- returns theWorldModeledEntity#getViewers()-- returns theHashSet<UUID>of players who can see the entityModeledEntity#getNametagBones()-- returnsList<Bone>of nametag bones (useful for placing additional text)ModeledEntity#getScaleModifier()/setScaleModifier(double)ModeledEntity#removeWithDeathAnimation()-- removes with the death animation (if one exists)ModeledEntity#removeWithMinimizedAnimation()-- removes with a scaling-down animationModeledEntity#remove()-- immediately removes the entity and all bonesDynamicEntity#setSyncMovement(boolean)DynamicEntity#isDamagesOnContact()/setDamagesOnContact(boolean)-- controls whether the entity damages players via hitbox contactBone#getBoneLocation()
Event Surface
Generic interaction events:
ModeledEntityLeftClickEventModeledEntityRightClickEventModeledEntityHitboxContactEventModeledEntityHitByProjectileEvent
Typed variants also exist for StaticEntity, DynamicEntity, and PropEntity.
Lifecycle event:
ResourcePackGenerationEvent-- fires when FMM finishes generating or regenerating the resource pack (on startup and on/fmm reload). Listen for this to trigger post-processing on the generated pack.
ModeledEntityHitByProjectileEvent And OBB Projectile Detection
FMM uses OBB (oriented bounding box) hit detection for projectiles against modeled entities. When a projectile intersects a modeled entity's OBB hitbox, FMM fires a ModeledEntityHitByProjectileEvent. This is a standard cancellable Bukkit event.
Key details:
- Arrow damage is calculated with support for the
POWERenchantment bonus PIERCINGenchantment is respected -- arrows can pass through to additional targets- Cancel the event to prevent damage and block the hit entirely
@EventHandler
public void onProjectileHitModel(ModeledEntityHitByProjectileEvent event) {
ModeledEntity target = event.getModeledEntity();
Projectile projectile = event.getProjectile();
// Cancel to prevent damage
event.setCancelled(true);
}
Item & Model Utilities
ModelItemFactory
Factory class for creating model-related ItemStacks programmatically.
// 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)-- creates a placement item for props. On 1.21.4+, automatically applies display model rendering if a display JSON exists.createCustomItem(String itemId, PropScriptConfigFields config)-- creates a custom item with name, lore, enchantments, and display model from the unified config.formatModelName(String modelId)-- utility that converts a model ID like01_em_flame_swordintoFlame Sword.
DisplayModelRegistry
Simple registry that tracks which models have a display JSON available.
// Check if a model has a display model JSON registered
boolean has3D = DisplayModelRegistry.hasDisplayModel("magic_sword");
register(String modelId)-- registers a model ID (called internally during reload)hasDisplayModel(String modelId)-- returnstrueif a.jsondisplay model exists for this modelgetRegisteredModels()-- returns an immutableSet<String>of all model IDs that have display models registeredshutdown()-- clears all registrations
ItemScriptManager
Manages the lifecycle of per-player Lua scripts for custom items (models with material: set in their YML config).
// 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)-- scans model YML configs for custom itemsupdateEquippedScripts(Player player)-- diffs equipped items against running scripts, firing equip/unequip hooksremovePlayer(Player player)-- shuts down all scripts for a player (call on quit)getItemDefinitions()-- returns the map of item ID toPropScriptConfigFields
ScriptedItemAPI
Public API for external plugins to integrate with FMM's scripted item system. This allows other plugins to stamp their own ItemStacks with FMM scripted item data (PDC tag + item model) so that FMM's Lua script hooks fire for those items, without FMM overriding the item's name, lore, or enchantments.
// 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)-- returnstrueif the item ID is registered in FMM's item definitionsapplyScriptedItemData(ItemStack itemStack, String itemId)-- stamps PDC tag and item model onto an existing ItemStack. Returnstrueon success,falseif the item ID is invalid or the ItemStack has no meta. Bow/crossbow note: if the givenitemIddoes not have a display model butitemId + "_idle"does (i.e. the item has bow/crossbow state models), the method automatically uses the_idlemodel as the display modelgetItemConfig(String itemId)-- returns thePropScriptConfigFieldsfor the given item ID, ornullif not found
EliteMobs uses this API internally via the scriptedItem config field. When an EliteMobs custom item sets scriptedItem: flame_blade, EliteMobs builds its item normally (name, lore, enchantments, level) then calls ScriptedItemAPI.applyScriptedItemData() to add FMM's model and script behavior on top.
PropScriptConfigFields
Unified configuration class for model YML config files. Used by both prop scripts and custom items.
# 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"
Key methods: isCustomItem(), getParsedMaterial(), getParsedEnchantments(), getScripts().
Lua Scripting
FreeMinecraftModels supports Lua scripts for both props and custom items through the MagmaCore 2.0 scripting engine. Script files are placed in plugins/FreeMinecraftModels/scripts/ and are bound to models via a sibling YML config next to the model file.
Prop Script Hooks
| Hook | Trigger |
|---|---|
on_spawn | Prop is spawned into the world |
on_game_tick | Every tick while the prop is alive |
on_zone_enter | A player enters the prop's zone |
on_zone_leave | A player leaves the prop's zone |
on_destroy | Prop is removed |
on_left_click | Player left-clicks the prop |
on_right_click | Player right-clicks the prop |
on_projectile_hit | A projectile hits the prop |
Item Script Hooks
Custom items (models with material: set) support 22 Lua hooks:
| Hook | Trigger |
|---|---|
on_equip | Item enters a tracked equipment slot |
on_unequip | Item leaves a tracked equipment slot |
on_game_tick | Every tick while the item is equipped |
on_attack_entity | Player attacks an entity while holding the item |
on_kill_entity | Player kills an entity while holding the item |
on_take_damage | Player takes damage while item is equipped |
on_shield_block | Player blocks with a shield |
on_shoot_bow | Player shoots a bow |
on_projectile_hit | A projectile fired by the player hits something |
on_projectile_launch | Player launches a projectile |
on_right_click | Player right-clicks with the item |
on_left_click | Player left-clicks with the item |
on_shift_right_click | Player shift-right-clicks with the item |
on_shift_left_click | Player shift-left-clicks with the item |
on_interact_entity | Player right-clicks an entity with the item |
on_swap_hands | Player swaps the item between hands |
on_drop | Player drops the item |
on_break_block | Player breaks a block while holding the item |
on_consume | Player consumes the item |
on_item_damage | Item takes durability damage |
on_fish | Player uses a fishing rod |
on_death | Player dies while item is equipped |
Item scripts receive context.item (with the item ID and player info) instead of context.prop.
Prop Script Context Table
Prop scripts receive a context table. Here is a summary of the key APIs -- see Lua Prop API for full details.
context.prop:
model_id-- the blueprint model namecurrent_location-- the prop's current locationplay_animation(name, blend, loop)-- plays the named animation (blend and loop default totrue)stop_animation()-- stops all current animationshurt_visual()-- plays the hurt (red flash) visual on the proppickup()-- removes the prop and drops its placement itemmount(player)-- makes a player ride the propdismount(player)-- removes a player from the propget_passengers()-- returns a list of players currently riding the propspawn_elitemobs_boss(filename, x, y, z)-- spawns an EliteMobs boss relative to the prop
context.event:
- Available in
on_left_click,on_right_click, andon_projectile_hit cancel(),uncancel(),is_cancelledplayer-- the player who triggered the event
context.world:
spawn_entity(entity_type, location)-- spawns a vanilla entityset_block_at(location, material)-- sets a block in the world- Plus particles, sounds, block queries, lightning, and nearby-entity lookups
Player objects (from context.event.player):
get_held_item()-- returns the item the player is holdingconsume_held_item()-- removes one of the held itemhas_item(material)-- checks if the player has an itemsend_message(text)-- sends a chat message to the playergame_mode-- the player's current game mode
Prop Script Example
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
Item Script Example
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
Notes
- FreeMinecraftModels is an installed-plugin dependency, not an embeddable library.
- If your plugin needs freshly imported models, call
ModeledEntityManager.reload()instead of trying to rebuild FreeMinecraftModels state yourself. - All plugins in the Nightbreak ecosystem now depend on MagmaCore 2.0.0-SNAPSHOT, which includes the shared Lua scripting engine used by FreeMinecraftModels prop scripts and EliteMobs Lua powers.