メインコンテンツまでスキップ

Luaスクリプティング:トラブルシューティング

This page covers common problems you may encounter when writing or debugging FreeMinecraftModels prop and item scripts, plus tips for working with the lazy config generation system. If you are looking for working examples, see Examples & Patterns. If you are just getting started, see Getting Started.

Shared Lua Engine

FMM uses the MagmaCore Lua scripting engine shared across Nightbreak plugins. For documentation on shared concepts like the sandbox, scheduler, zones, world API, entity tables, and player UI methods, see the MagmaCore Lua Scripting Engine page.


よくある問題

1. Config file not loading / Script not attached

Symptom: The prop spawns but does not respond to clicks or any hooks.

Causes and fixes:

  • No .yml config file exists yet. FMM generates the config lazily on first prop spawn. The first time a model is spawned, FMM creates the .yml config asynchronously with default values (enabled, no scripts). You must edit the generated config to add your script filenames and then respawn the prop.

  • The config has isEnabled: false. Open the .yml file next to the model file and set isEnabled: true.

  • The scripts: list is empty. Add your script filenames:

    isEnabled: true
    scripts:
    - my_script.lua
  • The .yml filename does not match the model filename. The config must have the same base name as the model file. For example, torch_01.fmmodel needs torch_01.yml in the same directory.


2. Script file not found

Symptom: Console shows: [FMM Scripts] Script 'my_script.lua' not found in scripts/ folder

Causes and fixes:

  • Wrong directory. Script files must be in plugins/FreeMinecraftModels/scripts/, not next to the model file.

  • Filename mismatch. The name in the .yml config must exactly match the filename in the scripts/ folder, including case and the .lua extension.

  • File not present. Double-check that the .lua file actually exists in the scripts/ folder.


3. Script does not load at all

Symptom: No console error, but no hooks fire.

Check the server console for Lua syntax errors during startup. The most common causes are:

  • Missing end to close a function or if block
  • Unmatched parentheses
  • Missing comma between hook definitions in the returned table
  • File does not end with .lua

If there is a Lua error, the console will print a [Lua] error block with the filename, line number, and a description.


4. Hook never fires

Symptom: The script loads (you see the [FMM Scripts] Bound script message), but a specific hook never triggers.

Verify the hook name is spelled exactly as listed in the hook reference. Common mistakes:

Wrong nameCorrect name
on_clickon_right_click or on_left_click
on_interacton_right_click
on_hiton_left_click
on_tickon_game_tick
on_removeon_destroy
on_arrow_hiton_projectile_hit

Also verify that the prop actually has a backing armor stand entity. Some prop configurations may not produce a clickable entity.


5. Timeout / execution budget exceeded

Symptom: Console shows a message like:

[Lua] my_script.lua took 73ms in 'on_game_tick' (limit: 50ms) -- script disabled to prevent lag.

The script was doing too much work in a single hook call. Common causes:

  • Iterating over too many entities in on_game_tick
  • Creating too many particles per tick
  • Running expensive loops without spreading work across ticks

Fix: Move heavy work behind a state-based cooldown or use scheduler:run_repeating() with a reasonable interval instead of on_game_tick.


6. context.event is nil in a click hook

This should not normally happen for on_left_click and on_right_click, but always guard with:

if context.event then
context.event.cancel()
end

Inside scheduler callbacks, context.event is always nil -- this is expected behavior. Event modification can only happen inside the event hook itself.


7. Animation does not play

Symptom: play_animation() returns false, or nothing visible happens.

Causes and fixes:

  • Wrong animation name. The name must exactly match what is defined in the model file. Check your .bbmodel or .fmmodel for the correct animation name.

  • Model has no animations. Not all models have animations. Verify the model file actually contains animation data.

  • Players are not in resource pack range. The animation is server-side, but players need the FMM resource pack loaded to see the model at all.


8. Particles do not appear

  • Verify the particle name is a valid Bukkit Particle enum value in UPPER_CASE: "FLAME", not "flame".
  • Verify the location is in a loaded chunk. If no players are nearby, the chunk may be unloaded.
  • Verify count is at least 1.
  • Some particles (like DUST) need specific extra data that the base spawn_particle() may not support. Use standard particles like FLAME, HEART, HAPPY_VILLAGER, NOTE, ENCHANT, etc.

9. Sound does not play

  • Verify the sound name is a valid Bukkit Sound enum constant in UPPER_CASE. Example: "BLOCK_NOTE_BLOCK_HARP", not "block.note_block.harp".
  • Verify the location coordinates are correct (not all zeros or NaN).
  • Verify volume is greater than 0.

10. State resets unexpectedly

context.state is per-prop-instance and persists for the prop's lifetime. If state seems to reset:

  • The prop may have been removed and respawned (each spawn creates a new instance).
  • You may be reading state in a scheduler callback using the wrong context variable. Always use the callback's own context parameter.

11. os library is not available

Symptom: Script crashes with an error like attempt to index nil (os).

The os library is completely removed from the Lua sandbox. You cannot use os.time(), os.clock(), or any other os function.

Fix: Use context.world:get_time() for world time, or track elapsed time manually using state flags and on_game_tick tick counters. For cooldowns, use context.state flags with scheduler:run_later().


12. Item script not activating

Symptom: The custom item is in the player's hand, but no item hooks fire.

Causes and fixes:

  • No material: field in the YML config. Item scripts only work on models that have material: set in their config. Without this field, FMM treats the model as a prop, not a custom item.

  • Missing fmm_item_id PDC key. The item in the player's inventory must have the fmm_item_id PersistentDataContainer key. Items obtained through vanilla commands or third-party plugins may lack this tag. Use /fmm giveitem <id> or the admin menu to get a properly tagged item.

  • Script filename not listed in the config. Verify the item's .yml config has the script filename in the scripts: list, just like props.


13. Item script activating then immediately deactivating

Symptom: You see the script bind and unbind in rapid succession in the console, or on_equip fires followed immediately by on_unequip.

Cause: Item equip tracking fires on slot change events. If you give yourself an item with a command and it goes into a non-active slot, or if your active slot changes during the give, the equip/unequip cycle can fire in quick succession.

Fix: After giving yourself the item with /fmm giveitem <id>, make sure to manually switch to the inventory slot containing the item. The script activates based on which slot is currently selected, not just whether the item is in the inventory.


14. Hook fires but script crashes on entity methods

Symptom: A hook like on_shift_right_click works, but the script crashes inside a scheduled callback with errors like attempt to call nil when calling entity:damage() or entity:push().

Cause: context.world:get_nearby_entities() returns ALL entities in range, including non-living entities (armor stands, dropped items, experience orbs, area effect clouds). These entities do not have living-entity methods like damage(), push(), or add_potion_effect().

Fix: Always guard with if entity.damage then before calling living-entity methods:

local entities = context.world:get_nearby_entities(x, y, z, radius)
for _, entity in ipairs(entities) do
if entity.damage then
-- Safe to call living entity methods
entity:damage(5.0)
entity:push(0, 0.5, 0)
end
end

15. context.player is nil in scheduled callbacks

Symptom: context.player is nil inside a scheduler:run_later() or scheduler:run_repeating() callback, even though it was available in the hook that created the callback.

Cause: The context is rebuilt lazily for each callback invocation. In some cases, especially if the player disconnects or the item is unequipped between scheduling and execution, context.player may not be available.

Fix: Capture the player reference from a closure variable before scheduling:

on_right_click = function(context)
local player = context.player
local player_loc = player.current_location

context.scheduler:run_later(20, function()
-- Use the captured 'player' variable, not context.player
if player.is_valid then
player:send_message("&aDelayed message!")
end
end)
end

遅延設定生成の仕組み

Understanding the lazy config system helps avoid confusion when setting up new props:

  1. First spawn: When a prop spawns and no sibling .yml file exists, FMM creates the config asynchronously. This means the file is written in a background thread and is not immediately available.

  2. Default values: The generated config has isEnabled: true and an empty scripts: [] list.

  3. No scripts on first spawn: Because the config is created after the prop has already spawned (and has no scripts listed), the prop will have no scripts attached on its first spawn.

  4. Edit and respawn: After FMM creates the config, you edit it to add your script filenames. The next time the prop spawns, scripts will be loaded.

  5. Config location: The .yml file is created in the same directory as the model file, with the same base name. For example:

    • Model: plugins/FreeMinecraftModels/models/fountain.fmmodel
    • Config: plugins/FreeMinecraftModels/models/fountain.yml
Quick setup workflow
  1. Place model in models/
  2. Place script in scripts/
  3. Spawn the prop once (generates the .yml)
  4. Edit the .yml to add scripts: [my_script.lua]
  5. Respawn the prop -- script is now active

エラーメッセージの読み方

When something goes wrong in a Lua prop script, the console prints a [Lua] error block. These messages tell you exactly which file, which line, which hook, and what went wrong in plain English.

A typical error looks like this:

[Lua] Error in 'my_door.lua' at line 12 during 'on_right_click':
[Lua] -> You tried to call a method or function that doesn't exist.
[Lua] -> Check the method name for typos, or make sure you're using ':' (colon) for method calls, not '.' (dot).
[Lua] -> Script has been disabled for this entity to prevent further errors.

The system translates common Lua errors into plain English:

Raw Lua errorWhat the console tells you
attempt to call nilYou tried to call a method or function that doesn't exist. Check for typos and : vs . usage.
index expected, got nilYou tried to access a field on something that is nil. Check that earlier code initialized it.
attempt to indexYou tried to access a property on a nil or invalid value.
bad argumentA function received the wrong type of argument. The message shows the expected vs. actual type.
TimeoutYour script took Xms in 'hook_name' (limit: 50ms) -- script disabled to prevent lag.
ヒント

Always read the full [Lua] error message before diving into the code. It usually points you straight to the fix.


ドキュメントにないメソッドが存在すると仮定しない

The FMM Lua API exposes a specific set of methods. Do not assume shorthand or alternative names exist. Common mistakes:

  • context.prop:get_location() -- does not exist. Use context.prop.current_location (a field, not a method).
  • context.prop:set_animation("open") -- does not exist. Use context.prop:play_animation("open", true, true).
  • context.event:setCancelled(true) -- does not exist. Use context.event.cancel().
  • context.cooldowns:check_local(...) -- does not exist in FMM. Use context.state with scheduler:run_later() for cooldowns.
  • context.player -- does not exist in FMM prop scripts (use context.world:get_nearby_players() to find players near the prop). It does exist in item scripts.
  • context.boss -- does not exist. That is EliteMobs. Use context.prop in FMM.

When in doubt, check the Prop API page. If it is not documented there, it does not exist.


デバッグのヒント

1. Use context.log:info() liberally

Add log messages at every step when debugging:

on_right_click = function(context)
context.log:info("Right click received!")
context.log:info("Event present: " .. tostring(context.event ~= nil))
context.log:info("State is_open: " .. tostring(context.state.is_open))
end

2. Check the console on startup

FMM logs [FMM Scripts] Bound script 'X' to prop 'Y' for each successful binding. If you do not see this message, the config or script was not loaded.

3. Verify the model file path

The .yml config must be a sibling of the model file (same directory, same base name). Verify this by checking:

  • Model file path: plugins/FreeMinecraftModels/models/my_model.fmmodel
  • Config file path: plugins/FreeMinecraftModels/models/my_model.yml

4. Test hooks individually

When building a complex script, start by testing each hook in isolation. Add one hook at a time and verify it fires before moving to the next.

5. Check for typos in hook names

The most common reason a hook does not fire is a misspelled hook name. The script will load without errors, but the misspelled hook function will be rejected during validation.


初心者向け学習パス

If you want to learn this system from scratch, this progression works well:

  1. Write a file with only api_version = 1 and on_spawn that logs a message.
  2. Add the script to a prop config and verify the log message appears.
  3. Add on_right_click and log when the prop is clicked.
  4. Add on_left_click with context.event.cancel() for invulnerability.
  5. Play an animation on right-click.
  6. Add a sound on right-click.
  7. Add state and toggle behavior.
  8. Add a zone watch for proximity detection.
  9. Only then move into complex multi-hook scripts with schedulers.

Each step builds on the previous one, and you can test at every stage.


次のステップ