Lua 腳本:入門指南
本頁帶你從空白檔案開始,撰寫可運作的 FreeMinecraftModels 互動道具腳本,並學習鉤子、上下文、道具 API 及腳本檔案的基本結構。
熟悉基礎後,請繼續閱讀:
- 道具 API —
context.prop、context.event、context.world及其他上下文 API - 範例與模式:可供學習與改寫的道具腳本,附有設定說明
- 疑難排解 — 常見錯誤、除錯技巧及品質檢查清單
Lua 道具腳本目前屬於實驗性功能。隨著 FreeMinecraftModels 開發,鉤子名稱、輔助方法及行為可能改變,請在正式伺服器使用前仔細測試。
FreeMinecraftModels 使用 MagmaCore Lua 執行環境。如果你寫過 EliteMobs Lua 能力,就會熟悉回傳表的檔案、api_version、鉤子、context、狀態、冷卻、排程及沙盒。確切的鉤子與上下文方法名稱仍取決於外掛:
- EliteMobs 腳本在 Boss 上執行,使用
on_boss_damaged_by_player、on_enter_combat等鉤子。 - FMM 道具腳本在道具上執行,使用
on_right_click、on_left_click、on_zone_enter等鉤子。 - 物品附魔使用獨立的自訂附魔上下文。
這裡的 context.world、context.zones、context.scheduler、context.state 及 context.log 是 FreeMinecraftModels/MagmaCore 版本。EliteMobs NPC 腳本使用相同的通用 MagmaCore 表,另加 context.npc;Boss 能力的部分表則使用 Boss 專屬實作。本頁介紹 FMM 道具的特有內容。
什麼是道具腳本
道具腳本是放在 plugins/FreeMinecraftModels/scripts/ 的獨立 .lua 檔案,由模型旁的 YAML 設定引用,在道具生成到世界時執行。
道具腳本的用途
它們適合實作:
- 回應點擊的門、拉桿、按鈕等互動道具
- 忽略預設左鍵傷害的裝飾道具
- 偵測玩家進入或離開範圍的接近觸發器
- 透過互動或計時器播放動畫的道具
- 被點擊或靠近時發聲的道具
- 超出靜態裝飾、需要額外邏輯的行為
純裝飾且無需互動的道具不需要腳本。
自訂物品與附魔
自訂物品仍在模型旁的 YAML 中指定 material,但效果現已改用帶命名空間的附魔。舊的裝備物品腳本執行環境已停用。帶非空 scripts: 清單的自訂物品會被略過,並在主控台顯示資訊訊息;其定義保持不變。
scripts/ 中被辨識為已停用裝備物品腳本的 Lua 檔案,會在探索階段之前及匯入之後保存在 plugins/MagmaCore/outdated files/FreeMinecraftModels/<archive batch>/scripts/。封存規則要求有效的舊腳本定義包含已停用的物品鉤子,例如 on_equip 或 on_attack_entity。道具腳本、僅使用共用鉤子的檔案、格式錯誤的腳本,以及 enchantments/ 中的現有效果,都不會歸入此類。復原方式請參閱已停用的設定檔。
目前的物品定義見自訂物品與魔法武器,效果見自訂附魔。道具的 scripts: 清單仍然有效。
本頁的目標讀者
本頁面向三類讀者:
- 熟悉 EliteMobs Lua,想學習 FMM 特有鉤子及 API 的人
- Lua 新手,需要名稱準確且完整的道具參考文件的人
- 使用 AI 起草腳本,需要辨識虛構 API 的人
撰寫實用腳本不需要先掌握整門 Lua 語言。多數情況下,只需知道:
- 如何在回傳表中定義有效鉤子
- 如何讀取
context的值 - 如何用
if ... then return end提前結束 - 如何準確呼叫所需的輔助方法
Lua 快速入門
多數腳本只用到變數(local x = 5)、函式(function foo() end)、條件(if x then ... end)、表({key = value})及 nil(表示沒有值)。語法不要求分號,區塊用 end 結束,而非大括號。
完整說明及範例見 MagmaCore Lua 腳本引擎 — Lua 快速入門。這是所有 Nightbreak 外掛共用的基礎。
檔案存放位置
腳本檔案
將 .lua 檔案放在中央腳本資料夾:
plugins/
FreeMinecraftModels/
scripts/
invulnerable.lua
interactive_door.lua
proximity_sound.lua
FMM 初始化腳本提供者時會遞迴尋找 plugins/FreeMinecraftModels/scripts/ 中的 .lua 檔案,並快取原始碼。綁定使用檔名而非相對路徑,因此子資料夾之間也不能重複命名。加入或編輯 Lua 後,先成功完成 /fmm reload,再建立新綁定。只重新生成道具不會重讀 Lua 原始碼。
為求清楚,請在模型的 scripts: 清單中包含 .lua 副檔名。FMM 也接受省略副檔名的項目,並在內部補上。磁碟上的檔案必須以 .lua 結尾,名稱區分大小寫。
模型與設定檔
每個模型可在同一目錄中擁有對應的 .yml 設定檔:
plugins/
FreeMinecraftModels/
models/
torch_01.fmmodel
torch_01.yml <-- script config for torch_01
scripts/
invulnerable.lua <-- referenced by torch_01.yml
該 .yml 將模型與腳本關聯。
設定檔格式
模型旁的 YAML 有以下欄位:
isEnabled: true
voxelize: false
solidify: false
scripts:
- invulnerable.lua
道具欄位如下:
| 欄位 | 類型 | 預設值 | 說明 |
|---|---|---|---|
isEnabled | 布林值 | true | 是否啟用定義 |
scripts | 字串清單 | [] | scripts/ 中的道具 Lua 檔名 |
voxelize | 布林值 | false | 將放置位置對齊方塊格線,旋轉對齊至 90 度 |
solidify | 布林值 | false | 為體素化道具加入透過封包呈現的屏障方塊 |
清單中的每個道具腳本都有獨立實例。手持物品則應定義 material、name、lore 及帶命名空間的 enchantments,詳見自訂物品。
設定延遲產生
道具生成時若沒有對應 .yml,FMM 會非同步建立包含 isEnabled: true 及空 scripts: 清單的預設設定。因此首次生成時沒有腳本,需要等待設定建立,再加入腳本檔名。
- 將模型放入
models/。 - 生成道具一次,讓 FMM 建立
.yml。 - 編輯
.yml,加入腳本檔名。 - 編輯 YAML 或 Lua 後,都應成功完成
/fmm reload,再放置新道具並檢查其日誌或互動。道具設定、放置檢查及選單腳本清單共用已準備好的目錄;僅重新生成道具不會重讀 YAML。
鉤子參考
每個 Lua 道具腳本回傳一個表。除了 api_version 及 priority,所有鍵都必須是下列鉤子之一。對應遊戲事件發生時,執行環境呼叫相應函式。
| 鉤子 | 觸發時機 | 說明 |
|---|---|---|
on_spawn | 道具生成到世界,或隨其區塊再次載入 | 每次繫結腳本時執行一次 |
on_game_tick | 每個伺服器 tick,20 TPS 時為 50 ms | 僅在定義此鉤子時啟用 |
on_destroy | 道具被永久移除 | 清理鉤子。道具所在區塊卸載或 FMM 重新載入時不會呼叫 |
on_left_click | 玩家左鍵點擊或攻擊道具 | context.event 包含 FMM 預設傷害取消標記 |
on_right_click | 玩家右鍵點擊道具 | context.event 包含 FMM 預設互動取消標記 |
on_zone_enter | 玩家進入監視區域 | 需要先設定區域監視 |
on_zone_leave | 玩家離開監視區域 | 需要先設定區域監視 |
on_projectile_hit | 拋射物擊中道具 | context.projectile 是該拋射物;context.event.player 是射擊者。請參閱道具 API |
物品效果
舊裝備物品鉤子已不再派送。效果應寫在自訂附魔中,使用其專用鉤子及上下文。不要將附魔 Lua 放進道具的 scripts: 清單,也不要原樣複製舊物品腳本。
最小檔案要求
每個 Lua 道具腳本必須 return 一個表。
必填與選填的頂層欄位
| 欄位 | 必填 | 類型 | 說明 |
|---|---|---|---|
api_version | 是 | 數字 | 目前必須為 1 |
priority | 否 | 數字 | 存在時會驗證,但 FMM 目前不按它排序,而是按 scripts: 清單順序執行 |
| 支援的鉤子鍵 | 否 | 函式 | 必須使用鉤子參考中的準確名稱 |
驗證規則
- 檔案必須回傳表。
api_version必填,目前必須為1。priority如果存在,必須是數字。- 其他頂層鍵必須是受支援的鉤子名稱。
- 每個鉤子的值必須是函式。
- 未知頂層鍵會被拒絕。
priority 有助於腳本在各個基於 MagmaCore 的執行環境間移植,但 FMM 的執行順序由設定決定。請按所需順序排列模型的 scripts: 清單。
輔助函式及區域常數應放在最後的 return 上方,而非回傳表內。
一步步撰寫第一個道具腳本
步驟1之前:準備設定
- 將
my_prop.fmmodel等模型放在plugins/FreeMinecraftModels/models/。 - 生成道具一次,以建立
.yml。 - 建立
plugins/FreeMinecraftModels/scripts/first_test.lua。 - 編輯
plugins/FreeMinecraftModels/models/my_prop.yml:
isEnabled: true
scripts:
- first_test.lua
- 儲存下方步驟 1 的 Lua 內容,執行
/fmm reload並確認成功。必要時重新生成道具。後續每次編輯 Lua 後也要成功重新載入。
步驟1:載入檔案
return {
api_version = 1,
on_spawn = function(context)
end
}
主控台沒有錯誤是有用的初步檢查。請用步驟2的明確日誌確認:
- 檔案是有效的 Lua
- FMM 在
scripts/中找到了它 - 設定正確引用了它
- 回傳表的結構正確
步驟2:產生可觀察的結果
return {
api_version = 1,
on_spawn = function(context)
context.log:info("Prop script loaded for: " .. (context.prop.model_id or "unknown"))
end
}
檢查主控台。出現日誌代表鉤子已執行。
步驟3:回應玩家點擊
return {
api_version = 1,
on_right_click = function(context)
context.log:info("Prop was right-clicked!")
end
}
在遊戲中右鍵點擊道具。出現訊息代表點擊鉤子正常運作。
步驟4:取消左鍵傷害
return {
api_version = 1,
on_left_click = function(context)
if context.event then
context.event.cancel()
end
end
}
這是附帶的 invulnerable.lua 使用的模式。它取消這次點擊造成的 FMM 預設道具傷害,不會讓底層實體免疫所有傷害來源。
步驟5:點擊時播放動畫
return {
api_version = 1,
on_right_click = function(context)
context.prop:play_animation("open", true, false)
end
}
這會要求在目前狀態 tick 之後播放不循環的「open」動畫,模型必須包含它。blend 不進行漸變;佇列只有一個位置,後續要求可能取代先前要求。終止死亡狀態可能拒絕要求。請在遊戲中檢查顯示結果,接受要求本身不證明播放。
什麼是 context?
每個鉤子函式接收一個名為 context 的參數,包含與道具、世界、區域等互動所需的操作及資料。
FMM 會建立並傳入它,你無需自行建立。共用 API context.state、context.log、context.cooldowns、context.scheduler、context.world 及 context.zones 的詳情見 MagmaCore Lua 腳本引擎。
主要 context API
以下是概要,完整參考見道具 API。
-
context.prop— 道具實體,僅用於道具腳本。提供model_id、current_location、play_animation()及stop_animation()。 -
context.player— 道具點擊及通用區域鉤子的觸發玩家;在on_projectile_hit中,若拋射物由玩家射出,則為該射擊者。在道具生命週期鉤子、排程回呼及不涉及玩家的鉤子中為nil。 -
context.event— 點擊鉤子中的 FMM 取消標記及玩家、on_projectile_hit中的拋射物命中事件及其射擊者,或通用區域鉤子中僅包含行為者的表。提供event.player、is_cancelled,點擊與拋射物命中時另提供cancel()/uncancel()。不暴露 Bukkit 專屬的target、block、projectile或item。沒有事件或玩家的鉤子,如on_spawn、on_game_tick,此值為nil。 -
context.projectile—on_projectile_hit中的拋射物實體,在其他所有鉤子中為nil。見on_projectile_hit。 -
context.state— 在腳本實例生命週期內保留的普通 Lua 表。見 context.state。 -
context.cooldowns— 區域及全域冷卻輔助方法。腳本層級冷卻通常使用context.cooldowns:check_local("key", ticks)。見 context.cooldowns。 -
context.log— 主控台日誌。見 context.log。 -
context.scheduler— 延遲及重複任務。見 context.scheduler。 -
context.world— 粒子、聲音、方塊查詢、閃電、附近實體等世界操作。見 context.world。 -
context.zones— 建立及監視球體、圓柱體、長方體等區域。見 context.zones。
方法語法:: 與 .
差異見 MagmaCore Lua 腳本引擎。FMM API 接受兩種形式。
可複製的起步範本
最小有效道具腳本
return {
api_version = 1,
on_spawn = function(context)
end
}
取消左鍵傷害
return {
api_version = 1,
on_left_click = function(context)
if context.event then
context.event.cancel()
end
end
}
互動道具範本
return {
api_version = 1,
on_spawn = function(context)
context.state.is_active = false
end,
on_right_click = function(context)
context.state.is_active = not context.state.is_active
if context.state.is_active then
context.prop:play_animation("activate", true, true)
else
context.prop:stop_animation()
end
end
}
較大檔案的結構
local ANIMATION_NAME = "idle"
local function do_something(context)
context.log:info("Doing something!")
end
return {
api_version = 1,
priority = 0,
on_spawn = function(context)
context.state.task_id = nil
end,
on_right_click = function(context)
do_something(context)
end,
on_destroy = function(context)
if context.state.task_id ~= nil then
context.scheduler:cancel(context.state.task_id)
end
end
}
第一個實際工作流程
從頭撰寫道具腳本時,按以下順序進行:
- 建立
.lua並讓on_spawn運作。 - 將腳本檔名加入道具的
.yml。 - 改用實際需要的鉤子,如
on_right_click。 - 先加入日誌,再加入動畫或效果。
- 加入一個實際效果,如動畫、聲音或粒子。
- 最後再加入輔助函式、狀態、排程邏輯或區域。
每次編輯 Lua 後儲存檔案並成功完成 /fmm reload,再檢查新行為。每個步驟只改一件事,讓日誌或可見效果說明哪些部分正常運作。
附帶腳本
FMM 會寫入缺少的四個預製 Lua 腳本,也會替換辨識出的舊預設原始碼,但保留其他既有編輯。若行為與目前預設不同,請檢查已安裝的檔案:
invulnerable.lua— 取消 FMM 預設左鍵傷害,不阻止所有可能的傷害來源。pickupable.lua:取消預設左鍵傷害,累計三次允許的攻擊後要求撿取。計數器屬於綁定,玩家之間共用;較早一次攻擊後的 100 伺服器 tick 任務會重設它。允許的攻擊要求受傷閃爍。腳本阻止受保護或地牢位置的操作,但具有 FMM 保護略過權限或管理員狀態的玩家例外。storage_double.lua:要求 54 格物品欄、開關動畫與聲音。採用相同的保護檢查與管理員例外,每 5 伺服器 tick 查詢檢視者追蹤。道具的物品欄由所有檢視者共用,並在最後一位檢視者關閉或區塊卸載時儲存。銷毀時要求drop_inventory(),它會先儲存開啟中的物品欄,因此放入尚未關閉之物品欄的物品也會一併掉落。詳情請見prop:open_inventory。storage_single.lua— 與上者相同,但為 3 列、27 格,而非 6 列。
更多範例見範例與模式。
Lua 沙盒
道具腳本在與 EliteMobs 相同的 LuaJ 沙盒中執行,限制相同。已移除的全域變數及可用標準函式庫函式清單見 MagmaCore Lua 腳本引擎。
下一步
- 道具 API —
context.prop、context.event、context.world、context.zones及context.scheduler的完整參考 - 範例與模式:附有解說與設定說明的道具腳本
- 疑難排解 — 常見問題、除錯及品質檢查
如果你也撰寫 EliteMobs Boss Lua 能力,沙盒、api_version、狀態表、冷卻及鉤子結構會很熟悉,但 Boss 上下文使用 EliteMobs 專用方法名稱。準確的 Boss API 見 EliteMobs Lua 文件。