Lua Scripting: Prop & Item API
This page covers every API available to FreeMinecraftModels prop and item scripts: context.prop, context.item, context.event, context.player, context.world, context.zones, context.scheduler, context.state, and context.log. If you are new to scripting, start with Getting Started first.
context.prop
The prop table provides information about the prop entity and methods to control its animations. This is rebuilt fresh for each hook call.
Fields
| Field | Type | Notes |
|---|---|---|
prop.model_id | string | The blueprint model name (e.g. "torch_01") |
prop.current_location | location table | The prop's position at the time the context was built |
The location table has the standard fields: x, y, z, world, yaw, pitch.
Example: reading prop info
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)
Plays a named animation on the prop model.
| Parameter | Type | Default | Notes |
|---|---|---|---|
name | string | required | The animation name as defined in the model file |
blend | boolean | true | Whether to blend with the current animation |
loop | boolean | true | Whether the animation loops |
Returns true if the animation was found and started, false otherwise.
Example
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()
Stops all currently playing animations on the prop.
Takes no parameters.
Example
return {
api_version = 1,
on_right_click = function(context)
context.prop:stop_animation()
end
}
prop:hurt_visual()
Plays the visual hurt animation (red tint flash) on the prop without dealing any actual damage to it.
Takes no parameters.
Example
return {
api_version = 1,
on_left_click = function(context)
-- Flash red when punched, but don't actually take damage
if context.event then
context.event.cancel()
end
context.prop:hurt_visual()
end
}
prop:pickup()
Removes the prop from the world and drops a placement paper item at its location. The dropped item can be right-clicked on a block to place the prop again.
Takes no parameters.
Example
return {
api_version = 1,
on_right_click = function(context)
-- Let players pick up the prop by right-clicking it
context.prop:pickup()
end
}
prop:mount(player)
Mounts a player onto the first available mount point seat on the prop. The model must have mount-point bones defined.
| Parameter | Type | Notes |
|---|---|---|
player | entity table | A player entity table (e.g. from context.event.player) |
Example
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)
Dismounts a player from their mount point seat on the prop.
| Parameter | Type | Notes |
|---|---|---|
player | entity table | A player entity table |
Example
return {
api_version = 1,
on_right_click = function(context)
local player = context.event and context.event.player
if player then
-- Toggle mount/dismount
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()
Returns a Lua array of entity tables for all current passengers on the prop.
Takes no parameters.
Example
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()
Returns whether this prop has mount-point bones defined in its model.
Takes no parameters. Returns true or false.
Example
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)
Spawns an EliteMobs custom boss at the given location. Requires EliteMobs to be installed on the server.
| Parameter | Type | Notes |
|---|---|---|
filename | string | The custom boss filename (e.g. "my_boss.yml") |
x | number | X coordinate |
y | number | Y coordinate |
z | number | Z coordinate |
Returns a living entity table for the spawned boss, or nil if EliteMobs is not installed or the boss file does not exist.
Example
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)
Opens a persistent chest inventory GUI for the player. Contents are saved to the prop's PersistentDataContainer when the inventory is closed, and restored when opened again.
| Parameter | Type | Default | Notes |
|---|---|---|---|
player | entity table | required | The player to show the inventory to |
title | string | required | The inventory title (supports & color codes) |
rows | int | 3 | Number of rows (1-6, where 6 = 54 slots = double chest) |
Returns true if the inventory was opened, false otherwise.
prop:is_viewing_inventory(player)
Returns whether the given player currently has this prop's inventory open.
| Parameter | Type | Notes |
|---|---|---|
player | entity table | The player to check |
Returns true or false.
Example: Close animation when inventory is closed
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)
Takes the written or writable book from the player's main hand and stores it on the prop.
| Parameter | Type | Notes |
|---|---|---|
player | entity table | The player holding the book |
Returns true if successful.
prop:read_book(player)
Opens the stored book for reading by the player.
| Parameter | Type | Notes |
|---|---|---|
player | entity table | The player to show the book to |
Returns true if a book was opened.
prop:take_book(player)
Returns the stored book to the player's inventory and removes it from the prop.
| Parameter | Type | Notes |
|---|---|---|
player | entity table | The player to give the book to |
Returns true if successful.
prop:has_book()
Returns whether a book is stored on this prop. Takes no parameters.
prop:drop_inventory()
Drops all stored inventory contents at the prop's location as item entities, then clears the stored data. Automatically closes the inventory for any players currently viewing it.
Takes no parameters. Returns true if successful.
prop:drop_book()
Drops the stored book at the prop's location as an item entity and clears the stored book data.
Takes no parameters. Returns true if successful.
prop:set_persistent_data(key, value)
Stores a string value on the prop's armor stand PersistentDataContainer. This data survives server restarts and chunk unloads.
| Parameter | Type | Notes |
|---|---|---|
key | string | A unique key name (stored under fmm_lua_<key> internally) |
value | string | The value to store. Use tostring() for numbers and booleans. |
Returns true if successful, false if the prop has no backing armor stand.
prop:get_persistent_data(key)
Retrieves a string value previously stored with set_persistent_data. Returns nil if the key has not been set.
| Parameter | Type | Notes |
|---|---|---|
key | string | The key name used in set_persistent_data |
Example: Persistent toggle state
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
The item table is available in item scripts only (not prop scripts). It provides information about the custom item and methods to manipulate it. This table is rebuilt fresh for each hook call.
Fields
| Field | Type | Notes |
|---|---|---|
item.id | string | The item type ID (the fmm_item_id from the YML config) |
item:material()
Returns the material name of the item as a string (e.g. "DIAMOND_SWORD", "STICK").
item:get_amount() / item:set_amount(n)
Gets or sets the stack size of the item.
| Parameter | Type | Notes |
|---|---|---|
n | int | The new stack amount |
item:consume(n)
Decrements the item's stack amount by n (default 1). If the resulting amount is 0 or less, the item is removed from the player's inventory.
| Parameter | Type | Default | Notes |
|---|---|---|---|
n | int | 1 | Amount to consume |
item:get_uses() / item:set_uses(n)
Gets or sets a custom use counter stored in the item's PersistentDataContainer. This is independent of vanilla durability and can be used to implement custom durability or charge systems.
| Parameter | Type | Notes |
|---|---|---|
n | int | The new use count |
item:get_name() / item:set_name(s)
Gets or sets the display name of the item. Supports color codes with &.
| Parameter | Type | Notes |
|---|---|---|
s | string | The new display name (e.g. "&b&lFrost Sword") |
item:get_lore() / item:set_lore(table)
Gets or sets the item's lore. get_lore() returns a table of strings (one per line). set_lore() takes a table of strings.
| Parameter | Type | Notes |
|---|---|---|
table | table | Array of strings, one per lore line |
Example: Item script that tracks uses
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()
Returns a table with current and max fields representing the item's vanilla durability, or nil if the item has no durability bar.
Example
local dur = context.item:get_durability()
if dur then
context.player:send_message("Durability: " .. dur.current .. "/" .. dur.max)
end
item:get_durability_percentage()
Returns the remaining durability as a 0.0 to 1.0 fraction, or nil if the item has no durability bar.
item:use_durability(amount, can_break)
Reduces the item's vanilla durability by a flat amount.
| Parameter | Type | Default | Notes |
|---|---|---|---|
amount | int | required | How many durability points to consume |
can_break | boolean | false | If true, the item is destroyed when durability runs out. If false, durability stops at 1. |
item:use_durability_percentage(fraction, can_break)
Reduces the item's vanilla durability by a percentage of its maximum.
| Parameter | Type | Default | Notes |
|---|---|---|---|
fraction | number | required | Fraction of max durability to consume (e.g. 0.1 = 10%) |
can_break | boolean | false | If true, the item is destroyed when durability runs out. If false, durability stops at 1. |
context.event
Event data for the current hook. Available in click, combat, and interaction hooks for both prop and item scripts. Returns nil in hooks that have no associated event (on_spawn, on_game_tick, on_destroy, on_zone_enter, on_zone_leave, on_equip).
Fields and Methods
| Field or Method | Type | Notes |
|---|---|---|
event.player | player entity table | The player who triggered the event. Available in on_left_click, on_right_click, and on_projectile_hit (the shooter, if it was a player). See Player Entity Methods for all fields and methods. |
event.is_cancelled | boolean | Whether the event is currently cancelled |
event.cancel() | function | Cancels the event (e.g. prevents damage or interaction) |
event.uncancel() | function | Un-cancels a previously cancelled event |
Not all events are cancellable. If the underlying Bukkit event does not implement Cancellable, event.cancel() and event.uncancel() will not be present and event.is_cancelled will always be false.
Example: Making a prop invulnerable
Example
return {
api_version = 1,
on_left_click = function(context)
if context.event then
context.event.cancel()
end
end
}
Example: Checking cancellation state
Example
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
}
Inside scheduled callbacks (scheduler:run_later, scheduler:run_repeating), context.event is always nil. Event modification can only happen during the event hook itself.
context.world
The world API is shared across all Nightbreak plugins. See context.world for the full reference.
FMM props use the same MagmaCore world table as EliteMobs bosses. All methods documented on the global page (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, spawn_firework) are available in FMM. See the MagmaCore world API for full details on world:raycast() (cast a ray and detect hit entities/blocks) and world:spawn_firework() (spawn firework rockets with custom colors and shapes). EliteMobs extends the world table with additional methods for spawning bosses, reinforcements, and more -- see EliteMobs World & Environment.
Player Entity Methods
Player entity tables are returned from context.event.player, context.world:get_nearby_players(), and zone callbacks.
The entity tables, living entity methods, player-specific methods, and Player UI methods are shared across all Nightbreak plugins. See the MagmaCore Lua Scripting Engine for the full reference covering entity base fields, living entity fields and methods, player-specific fields and methods, and Player UI Methods. New player methods include player:get_target_entity() (raycast targeting), player:get_eye_location(), player:get_look_direction(), player:send_block_change() (per-player fake blocks), and player:reset_block() -- see Player-Specific Methods for details.
context.zones
The zones API is shared across all Nightbreak plugins. See context.zones for the full reference.
context.scheduler
The scheduler API is shared across all Nightbreak plugins. See context.scheduler for the full reference.
context.state
The state API is shared across all Nightbreak plugins. See context.state for the full reference.
context.log
The logging API is shared across all Nightbreak plugins. See context.log for the full reference.
Runtime Model
One Runtime Per Script Instance
Every prop entity that has scripts attached gets its own independent Lua runtime instance. When the prop spawns, FMM loads the Lua source, evaluates it in a fresh sandboxed environment, and stores the returned table. When the prop is removed, the runtime is shut down.
For item scripts, one runtime is created per (player, itemId) pair. When a player equips a custom item, FMM creates a script instance for that player and item type. When the item is unequipped, the runtime is shut down.
This means:
- Local variables declared at file scope are private to that script instance.
context.stateis completely isolated between instances, even if they share the same script file.
Scheduled Task Ownership
All tasks created through context.scheduler are owned by the runtime that created them. When a prop is removed:
- The runtime shuts down.
- Every owned task -- both one-shot and repeating -- is automatically cancelled.
- All zone watches are cleared.
Execution Budget
Every hook invocation and every callback invocation is timed. If a single call takes longer than 50 milliseconds, the script is disabled with a console warning:
[Lua] my_script.lua took 73ms in 'on_game_tick' (limit: 50ms) -- script disabled to prevent lag.
To stay within budget:
- Avoid unbounded loops inside hooks.
- Keep
on_game_tickhandlers lightweight -- they run every single tick. - Use
context.scheduler:run_repeating(...)to spread work across ticks.
Complete Hook Reference
This table lists all hooks available across both prop and item scripts.
Prop Hooks (8)
| Hook | Fires when | context.event |
|---|---|---|
on_spawn | Prop spawns into the world | nil |
on_game_tick | Every server tick (50ms) | nil |
on_destroy | Prop is removed | nil |
on_left_click | Player left-clicks the prop | damage event |
on_right_click | Player right-clicks the prop | interaction event |
on_projectile_hit | Projectile hits the prop | projectile hit event |
on_zone_enter | Player enters a watched zone | nil |
on_zone_leave | Player leaves a watched zone | nil |
Item Hooks (22)
| Hook | Category | Fires when | context.event |
|---|---|---|---|
on_attack_entity | Combat | Player attacks an entity | damage event |
on_kill_entity | Combat | Player kills an entity | death event |
on_take_damage | Combat | Player takes damage | damage event |
on_shield_block | Combat | Player blocks with shield | damage event |
on_shoot_bow | Combat | Player shoots a bow | bow shoot event |
on_projectile_hit | Combat | Player's projectile hits | projectile hit event |
on_projectile_launch | Combat | Player launches projectile | launch event |
on_right_click | Interaction | Player right-clicks | interact event |
on_left_click | Interaction | Player left-clicks | interact event |
on_shift_right_click | Interaction | Player shift+right-clicks | interact event |
on_shift_left_click | Interaction | Player shift+left-clicks | interact event |
on_interact_entity | Interaction | Player right-clicks entity | entity interact event |
on_equip | Equipment | Item enters active slot | nil |
on_unequip | Equipment | Item leaves active slot | nil |
on_swap_hands | Equipment | Swaps main/off hand | swap event |
on_drop | Equipment | Player drops item | drop event |
on_break_block | Utility | Player breaks block | block break event |
on_consume | Utility | Player consumes item | consume event |
on_item_damage | Utility | Item takes durability damage | item damage event |
on_fish | Utility | Player uses fishing rod | fish event |
on_death | Utility | Player dies while equipped | death event |
on_game_tick | Lifecycle | Every tick while equipped | nil |
Next Steps
- Examples & Patterns -- complete working scripts for props and items with walkthroughs
- Troubleshooting -- common issues, debugging tips, and a QC checklist
- Getting Started -- file structure, hooks, first script walkthrough