Lua 腳本:道具與物品 API
此頁面涵蓋 FreeMinecraftModels 道具與物品腳本可用的所有 API:context.prop、context.item、context.event、context.player、context.world、context.zones、context.scheduler、context.state 和 context.log。如果你剛接觸腳本,請先從 入門 開始。
context.prop
prop 表格提供道具實體的資訊以及控制其動畫的方法。每次鉤子呼叫時都會重新建構。
欄位
| 欄位 | 類型 | 說明 |
|---|---|---|
prop.model_id | string | 藍圖模型名稱(例如 "torch_01") |
prop.current_location | location 表格 | 建構 context 時道具的位置 |
位置表格擁有標準欄位:x、y、z、world、yaw、pitch。
範例:讀取道具資訊
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)
在道具模型上播放指定名稱的動畫。
| 參數 | 類型 | 預設值 | 說明 |
|---|---|---|---|
name | string | 必填 | 模型檔案中定義的動畫名稱 |
blend | boolean | true | 是否與當前動畫混合 |
loop | boolean | true | 動畫是否循環 |
如果找到動畫且已啟動則回傳 true,否則回傳 false。
範例
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()
停止道具上所有當前播放的動畫。
不接受參數。
範例
return {
api_version = 1,
on_right_click = function(context)
context.prop:stop_animation()
end
}
prop:hurt_visual()
在道具上播放視覺受傷動畫(紅色色調閃爍),不會對道具造成任何實際傷害。
不接受參數。
範例
return {
api_version = 1,
on_left_click = function(context)
-- 被打時閃紅,但不實際受到傷害
if context.event then
context.event.cancel()
end
context.prop:hurt_visual()
end
}
prop:pickup()
從世界中移除道具,並在其位置掉落放置紙質物品。掉落的物品可以右鍵點擊方塊以再次放置該道具。
不接受參數。
範例
return {
api_version = 1,
on_right_click = function(context)
-- 讓玩家可以右鍵點擊以拾起道具
context.prop:pickup()
end
}
prop:mount(player)
將玩家放上道具上第一個可用的坐騎點座位。模型必須定義了坐騎點骨骼。
| 參數 | 類型 | 說明 |
|---|---|---|
player | entity 表格 | 玩家實體表格(例如來自 context.event.player) |
範例
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)
將玩家從道具上的坐騎點座位移開。
| 參數 | 類型 | 說明 |
|---|---|---|
player | entity 表格 | 玩家實體表格 |
範例
return {
api_version = 1,
on_right_click = function(context)
local player = context.event and context.event.player
if player then
-- 切換騎上/下來
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()
回傳一個 Lua 陣列,包含道具上所有目前乘客的實體表格。
不接受參數。
範例
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()
回傳此道具的模型是否定義了坐騎點骨骼。
不接受參數。回傳 true 或 false。
範例
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)
在指定位置生成 EliteMobs 自訂 Boss。需要伺服器上安裝 EliteMobs。
| 參數 | 類型 | 說明 |
|---|---|---|
filename | string | 自訂 Boss 的檔名(例如 "my_boss.yml") |
x | number | X 座標 |
y | number | Y 座標 |
z | number | Z 座標 |
回傳已生成 Boss 的生物實體表格,如果未安裝 EliteMobs 或 Boss 檔案不存在則回傳 nil。
範例
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)
為玩家開啟一個持久化的箱子物品欄 GUI。物品欄關閉時內容會儲存到道具的 PersistentDataContainer,再次開啟時會還原。
| 參數 | 類型 | 預設值 | 說明 |
|---|---|---|---|
player | entity 表格 | 必填 | 要顯示物品欄的玩家 |
title | string | 必填 | 物品欄標題(支援 & 顏色代碼) |
rows | int | 3 | 列數(1-6,其中 6 = 54 個格子 = 大型箱子) |
如果物品欄已開啟則回傳 true,否則回傳 false。
prop:is_viewing_inventory(player)
回傳指定的玩家目前是否開啟著此道具的物品欄。
| 參數 | 類型 | 說明 |
|---|---|---|
player | entity 表格 | 要檢查的玩家 |
回傳 true 或 false。
範例:物品欄關閉時關閉動畫
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)
從玩家的主手取走已寫成或可寫的書,並儲存到道具上。
| 參數 | 類型 | 說明 |
|---|---|---|
player | entity 表格 | 持有書的玩家 |
成功時回傳 true。
prop:read_book(player)
開啟儲存的書讓玩家閱讀。
| 參數 | 類型 | 說明 |
|---|---|---|
player | entity 表格 | 要顯示書的玩家 |
如果開啟了一本書則回傳 true。
prop:take_book(player)
將儲存的書歸還到玩家的物品欄,並從道具中移除。
| 參數 | 類型 | 說明 |
|---|---|---|
player | entity 表格 | 接收書的玩家 |
成功時回傳 true。
prop:has_book()
回傳此道具上是否儲存了一本書。不接受參數。
prop:drop_inventory()
在道具的位置以物品實體形式掉落所有儲存的物品欄內容,然後清除儲存的資料。自動關閉任何正在檢視該物品欄的玩家視窗。
不接受參數。成功時回傳 true。
prop:drop_book()
在道具的位置以物品實體形式掉落儲存的書,並清除儲存的書資料。
不接受參數。成功時回傳 true。
prop:set_persistent_data(key, value)
將字串值儲存到道具的 armor stand PersistentDataContainer。此資料能在伺服器重啟和區塊卸載後保留。
| 參數 | 類型 | 說明 |
|---|---|---|
key | string | 唯一鍵名(在內部儲存於 fmm_lua_<key>) |
value | string | 要儲存的值。對數字和布林值使用 tostring()。 |
成功時回傳 true,如果道具沒有支援的 armor stand 則回傳 false。
prop:get_persistent_data(key)
擷取先前以 set_persistent_data 儲存的字串值。如果該鍵尚未設定則回傳 nil。
| 參數 | 類型 | 說明 |
|---|---|---|
key | string | set_persistent_data 中使用的鍵名 |
範例:持久化的切換狀態
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
item 表格僅在物品腳本中可用(道具腳本不可用)。它提供自訂物品的資訊與操作該物品的方法。此表格每次鉤子呼叫時都會重新建構。
欄位
| 欄位 | 類型 | 說明 |
|---|---|---|
item.id | string | 物品類型 ID(來自 YML 設定的 fmm_item_id) |
item:material()
回傳該物品的材質名稱字串(例如 "DIAMOND_SWORD"、"STICK")。
item:get_amount() / item:set_amount(n)
取得或設定物品的堆疊大小。
| 參數 | 類型 | 說明 |
|---|---|---|
n | int | 新的堆疊數量 |
item:consume(n)
將物品的堆疊數量減去 n(預設 1)。如果結果數量為 0 或更少,物品會從玩家的物品欄中移除。
| 參數 | 類型 | 預設值 | 說明 |
|---|---|---|---|
n | int | 1 | 要消耗的數量 |
item:get_uses() / item:set_uses(n)
取得或設定儲存在物品 PersistentDataContainer 中的自訂使用次數計數器。此計數器獨立於原版耐久度,可用於實作自訂耐久度或充能系統。
| 參數 | 類型 | 說明 |
|---|---|---|
n | int | 新的使用次數 |
item:get_name() / item:set_name(s)
取得或設定物品的顯示名稱。支援使用 & 的顏色代碼。
| 參數 | 類型 | 說明 |
|---|---|---|
s | string | 新的顯示名稱(例如 "&b&lFrost Sword") |
item:get_lore() / item:set_lore(table)
取得或設定物品的物品說明。get_lore() 回傳字串表格(每行一個)。set_lore() 接受字串表格。
| 參數 | 類型 | 說明 |
|---|---|---|
table | table | 字串陣列,每行物品說明一個 |
範例:追蹤使用次數的物品腳本
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()
回傳一個包含 current 和 max 欄位的表格,表示物品的原版耐久度,如果該物品沒有耐久度條則回傳 nil。
範例
local dur = context.item:get_durability()
if dur then
context.player:send_message("Durability: " .. dur.current .. "/" .. dur.max)
end
item:get_durability_percentage()
以 0.0 到 1.0 的分數回傳剩餘耐久度,如果該物品沒有耐久度條則回傳 nil。
item:use_durability(amount, can_break)
將物品的原版耐久度減少一個固定數值。
| 參數 | 類型 | 預設值 | 說明 |
|---|---|---|---|
amount | int | 必填 | 要消耗的耐久度點數 |
can_break | boolean | false | 若為 true,耐久度耗盡時物品會被銷毀。若為 false,耐久度會停在 1。 |
item:use_durability_percentage(fraction, can_break)
將物品的原版耐久度減少其最大值的一個百分比。
| 參數 | 類型 | 預設值 | 說明 |
|---|---|---|---|
fraction | number | 必填 | 要消耗的最大耐久度的分數(例如 0.1 = 10%) |
can_break | boolean | false | 若為 true,耐久度耗盡時物品會被銷毀。若為 false,耐久度會停在 1。 |
context.event
當前鉤子的事件資料。可用於道具和物品腳本的點擊、戰鬥及互動鉤子中。在沒有關聯事件的鉤子中回傳 nil(on_spawn、on_game_tick、on_destroy、on_zone_enter、on_zone_leave、on_equip)。
欄位與方法
| 欄位或方法 | 類型 | 說明 |
|---|---|---|
event.player | 玩家實體表格 | 觸發事件的玩家。在 on_left_click、on_right_click 和 on_projectile_hit(如果是玩家則為射擊者)中可用。請參閱 玩家實體方法 以了解所有欄位和方法。 |
event.is_cancelled | boolean | 事件目前是否被取消 |
event.cancel() | function | 取消事件(例如防止傷害或互動) |
event.uncancel() | function | 取消先前取消的事件 |
並非所有事件都可取消。如果底層的 Bukkit 事件未實作 Cancellable,event.cancel() 和 event.uncancel() 將不會存在,並且 event.is_cancelled 永遠為 false。
範例:讓道具無敵
範例
return {
api_version = 1,
on_left_click = function(context)
if context.event then
context.event.cancel()
end
end
}
範例:檢查取消狀態
範例
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
}
在排程的回呼內部(scheduler:run_later、scheduler:run_repeating),context.event 永遠為 nil。事件修改只能在事件鉤子本身內進行。
context.world
world API 在所有 Nightbreak 外掛之間共用。請參閱 context.world 以了解完整參考。
FMM 道具使用與 EliteMobs Boss 相同的 MagmaCore world 表格。全域頁面上記錄的所有方法(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)在 FMM 中都可用。請參閱 MagmaCore world API 以了解 world:raycast()(投射射線並偵測命中的實體/方塊)和 world:spawn_firework()(生成具有自訂顏色和形狀的煙火)的完整細節。EliteMobs 用其他用於生成 Boss、增援等的方法擴展了 world 表格 -- 請參閱 EliteMobs World & Environment。
玩家實體方法
玩家實體表格從 context.event.player、context.world:get_nearby_players() 和區域回呼傳回。
實體表格、生物實體方法、玩家專屬方法和玩家 UI 方法在所有 Nightbreak 外掛之間共用。請參閱 MagmaCore Lua 腳本引擎 以了解涵蓋實體基本欄位、生物實體欄位和方法、玩家專屬欄位和方法以及 玩家 UI 方法 的完整參考。新的玩家方法包括 player:get_target_entity()(光線追蹤瞄準)、player:get_eye_location()、player:get_look_direction()、player:send_block_change()(每位玩家的假方塊)和 player:reset_block() -- 請參閱 玩家專屬方法 以了解詳情。
FMM 專屬實體欄位
每個在 FMM 腳本中建構的實體表格都會自動取得這些額外欄位(透過 FMM 的 LuaEntityEnricher):
| 欄位 | 類型 | 說明 |
|---|---|---|
entity.is_modeled | boolean | 若此 Bukkit 實體是 ModeledEntity 的底層實體則為 true |
entity.is_prop | boolean | 若此實體是支援 PropEntity 的 armor stand 則為 true |
entity.model | 表格或 nil | 僅在 is_modeled = true 時填入(見下方) |
當 entity.model 存在時,它會公開:
| 欄位 / 方法 | 說明 |
|---|---|
model.model_id | 藍圖模型名稱(例如 "dragon") |
model.is_dynamic | 若這是 DynamicEntity(附加到生物實體)則為 true |
model:play_animation(name, blend, loop) | 播放指定名稱的動畫。成功時回傳 true |
model:stop_animations() | 停止所有當前動畫 |
model:remove() | 立即移除模型化實體及其所有骨骼 |
on_attack_entity = function(context)
local target = context.event.target
if target and target.is_modeled then
target.model:play_animation("hurt", true, false)
end
end
EliteMobs 實體欄位
當安裝了 EliteMobs 時,FMM 會轉發到 EliteMobs 的 enricher,使相同的實體表格也公開:
| 欄位 | 類型 | 說明 |
|---|---|---|
entity.is_elite | boolean | 若實體由 EliteMobs 追蹤則為 true |
entity.is_custom_boss | boolean | 若它是自訂 Boss 設定則為 true |
entity.is_significant_boss | boolean | 對於 healthMultiplier > 1 的自訂 Boss 為 true(過濾掉雜魚命名怪物) |
entity.elite | 表格或 nil | 僅在 is_elite = true 時填入。包含 level、name、health、max_health、health_multiplier、damage_multiplier、is_custom_boss,加上 elite:remove() |
context.zones
zones API 在所有 Nightbreak 外掛之間共用。請參閱 context.zones 以了解完整參考。
context.scheduler
scheduler API 在所有 Nightbreak 外掛之間共用。請參閱 context.scheduler 以了解完整參考。
context.state
state API 在所有 Nightbreak 外掛之間共用。請參閱 context.state 以了解完整參考。
context.log
logging API 在所有 Nightbreak 外掛之間共用。請參閱 context.log 以了解完整參考。
執行階段模型
每個腳本實例一個執行階段
每個附加了腳本的道具實體都會獲得自己獨立的 Lua 執行階段實例。當道具生成時,FMM 會載入 Lua 原始碼,在一個全新的沙箱化環境中對其求值,並儲存回傳的表格。當道具被移除時,執行階段會關閉。
對於物品腳本,每個(player, itemId)對會建立一個執行階段。當玩家裝備自訂物品時,FMM 會為該玩家和物品類型建立一個腳本實例。當物品被卸下時,執行階段會關閉。
這表示:
- 在檔案範圍宣告的本地變數對該腳本實例是私有的。
context.state在實例之間完全隔離,即使它們共用相同的腳本檔案。
排程任務歸屬
所有透過 context.scheduler 建立的任務都歸屬於建立它們的執行階段。當道具被移除時:
- 執行階段關閉。
- 每個歸屬的任務 -- 一次性與重複的 -- 都會自動取消。
- 所有區域監視都會被清除。
Cooldown 範圍
共用的腳本引擎公開了 context.cooldowns:set_local、:check_local、:set_global 和 :check_global(請參閱 MagmaCore cooldowns 參考)。FMM 將那些儲存範圍劃分如下:
| 腳本類型 | Local 儲存範圍 | Global 儲存範圍 |
|---|---|---|
| 道具腳本 | 每個 ScriptInstance(道具 + 腳本檔) | 每個 PropEntity(與繫結到該道具的每個腳本共用) |
| 物品腳本 | 每個 (player, itemId, scriptFile) 三元組 — 即使物品每次離開有效槽位時腳本實例都被拆除,仍能在重新裝備後持久存在 | 每位玩家(與該玩家執行的每個 FMM 物品腳本共用) |
由於物品腳本在每次裝備/卸下循環時都會被拆除並重建,物品冷卻時間會保存在以玩家 UUID 為鍵的靜態映射中,而不是放在 ScriptInstance 上。這就是為什麼當你把物品換出快捷欄再換回來後,物品冷卻時間仍然有效。
執行預算
每次鉤子呼叫和每次回呼呼叫都會計時。如果單次呼叫耗時超過 50 毫秒,腳本會被停用並在主控台發出警告:
[Lua] my_script.lua took 73ms in 'on_game_tick' (limit: 50ms) -- script disabled to prevent lag.
要保持在預算內:
- 避免在鉤子內進行無界迴圈。
- 保持
on_game_tick處理器輕量 -- 它們每個 tick 都會執行。 - 使用
context.scheduler:run_repeating(...)將工作分散到多個 tick。
完整鉤子參考
此表格列出道具與物品腳本所有可用的鉤子。
道具鉤子(8 個)
| 鉤子 | 觸發時機 | context.event |
|---|---|---|
on_spawn | 道具生成到世界中 | nil |
on_game_tick | 每個伺服器 tick(50 毫秒) | nil |
on_destroy | 道具被移除 | nil |
on_left_click | 玩家左鍵點擊道具 | damage 事件 |
on_right_click | 玩家右鍵點擊道具 | interaction 事件 |
on_projectile_hit | 拋射物擊中道具 | projectile hit 事件 |
on_zone_enter | 玩家進入受監視區域 | nil |
on_zone_leave | 玩家離開受監視區域 | nil |
物品鉤子(22 個)
| 鉤子 | 類別 | 觸發時機 | context.event |
|---|---|---|---|
on_attack_entity | 戰鬥 | 玩家攻擊實體 | damage 事件 |
on_kill_entity | 戰鬥 | 玩家擊殺實體 | death 事件 |
on_take_damage | 戰鬥 | 玩家受到傷害 | damage 事件 |
on_shield_block | 戰鬥 | 玩家用盾牌格擋 | damage 事件 |
on_shoot_bow | 戰鬥 | 玩家射出弓箭 | bow shoot 事件 |
on_projectile_hit | 戰鬥 | 玩家的拋射物擊中目標 | projectile hit 事件 |
on_projectile_launch | 戰鬥 | 玩家發射拋射物 | launch 事件 |
on_right_click | 互動 | 玩家右鍵點擊 | interact 事件 |
on_left_click | 互動 | 玩家左鍵點擊 | interact 事件 |
on_shift_right_click | 互動 | 玩家 shift+右鍵點擊 | interact 事件 |
on_shift_left_click | 互動 | 玩家 shift+左鍵點擊 | interact 事件 |
on_interact_entity | 互動 | 玩家右鍵點擊實體 | entity interact 事件 |
on_equip | 裝備 | 物品進入有效槽位 | nil |
on_unequip | 裝備 | 物品離開有效槽位 | nil |
on_swap_hands | 裝備 | 主副手切換 | swap 事件 |
on_drop | 裝備 | 玩家丟棄物品 | drop 事件 |
on_break_block | 公用 | 玩家破壞方塊 | block break 事件 |
on_consume | 公用 | 玩家消耗物品 | consume 事件 |
on_item_damage | 公用 | 物品耐久度受損 | item damage 事件 |
on_fish | 公用 | 玩家使用釣魚竿 | fish 事件 |
on_death | 公用 | 玩家裝備期間死亡 | death 事件 |
on_game_tick | 生命週期 | 裝備期間每個 tick | nil |