Lua Scripting:入門指南
本頁將教你為 FreeMinecraftModels prop 撰寫第一個 Lua script,從一個空白檔案一路到一個可運作的互動式 prop。讀完之後,你將理解 hook、context、Prop API 以及每個 prop script 檔案的通用架構。
熟悉基礎知識後,請繼續閱讀配套頁面:
- Prop API --
context.prop、context.event、context.world和其他 context API - 範例與模式 -- 可供學習和改寫的完整可運行 script
- 疑難排解 -- 常見錯誤、除錯技巧和 QC 檢查清單
Lua prop script 目前為實驗性功能。隨著 FreeMinecraftModels 的演進,hook 名稱、輔助方法和行為仍可能發生變化,因此在正式伺服器上使用前請仔細測試。
FreeMinecraftModels 與 EliteMobs 共享同一個 Lua 引擎(Magmacore)。如果你已經在為 EliteMobs 撰寫 Lua 能力,核心概念 -- hook、context、api_version、scheduler、區域和 sandbox -- 是相同的。差異在於:
- EliteMobs 的 script 運行在 Boss 上,擁有
on_boss_damaged_by_player、on_enter_combat等 hook。 - FMM 的 script 運行在 prop 上,擁有
on_right_click、on_left_click、on_projectile_hit等 hook。
context.world、context.zones、context.scheduler、context.state 和 context.log API 在兩個 plugin 中完全相同。本頁僅涵蓋 FMM prop 特有的內容。
什麼是 Prop Script
Prop script 是位於 plugins/FreeMinecraftModels/scripts/ 資料夾中的獨立 .lua 檔案。它們透過模型檔案旁邊的 YAML config 檔案引用,並在 prop 被生成到世界中時執行。
Prop Script 擅長什麼
Prop script 在以下場景中表現出色:
- 回應玩家點擊的互動式 prop(門、拉桿、按鈕)
- 玩家無法破壞的無敵裝飾 prop
- 偵測玩家進入或離開區域的接近觸發器
- 在互動或計時器觸發時播放動畫的 prop
- 被點擊或靠近時播放聲音的 prop
- 任何需要超越靜態裝飾的邏輯的 prop 行為
如果你的 prop 純粹是裝飾性的且不需要互動,則不需要 script。
本頁的目標讀者
本頁面面向三類讀者:
- 已經了解 EliteMobs Lua scripting,想學習 FMM 特有 hook 和 API 的人
- Lua scripting 新手,需要完整且名稱精確的 prop 參考的人
- 使用 AI 起草 prop script,需要足夠細節來辨別 AI 是否編造了虛假內容的人
你不需要在撰寫有用的 prop script 之前成為一名完整的 Lua 開發者。對於大多數實用的 prop script,你真正需要的只是:
- 如何在回傳的表中放置有效的 hook
- 如何從
context讀取值 - 如何用
if ... then return end提前退出 - 如何精確呼叫幾個輔助方法
Lua 快速入門
如果你完全沒接觸過 Lua,以下是你需要的最少語法。
變數
使用 local 儲存一個值:
local animation_name = "open"
local sound_volume = 1.0
函式
函式是可重複使用的邏輯區塊:
local function log_click(context)
context.log:info("Prop was clicked!")
end
if 檢查
當某件事只應在某些情況下發生時使用 if:
if context.event == nil then
return
end
nil
nil 表示「無值」。你會經常檢查它:
if context.event ~= nil then
context.event.cancel()
end
表
Lua 使用表來表示具有命名鍵的物件以及回傳的 script 定義:
return {
api_version = 1,
on_spawn = function(context)
end
}
註解
使用 -- 新增註解:
-- Cancel the damage event so the prop cannot be broken
context.event.cancel()
如需更詳細的 Lua 入門,請參閱 EliteMobs 入門指南 頁面。語法基礎完全相同。
檔案存放位置
Script 檔案
將 .lua 檔案放在中央 scripts 資料夾中:
plugins/
FreeMinecraftModels/
scripts/
invulnerable.lua
interactive_door.lua
proximity_sound.lua
FMM 在啟動時會發現 plugins/FreeMinecraftModels/scripts/ 中的所有 .lua 檔案。
模型檔案和 Config 檔案
每個模型檔案可以在同一目錄中有一個對應的 .yml config 檔案:
plugins/
FreeMinecraftModels/
models/
torch_01.fmmodel
torch_01.yml <-- torch_01 的 script config
scripts/
invulnerable.lua <-- 被 torch_01.yml 引用
.yml config 是連接模型與其 script 的橋樑。
Config 檔案格式
模型檔案旁邊的 YAML config 檔案有兩個欄位:
isEnabled: true
scripts:
- invulnerable.lua
| 欄位 | 類型 | 預設值 | 說明 |
|---|---|---|---|
isEnabled | boolean | true | 此 prop 的 script 是否啟用 |
scripts | 字串列表 | [] | scripts/ 資料夾中 .lua 檔案的檔名 |
你可以將多個 script 附加到同一個 prop。每個 script 都是獨立的實例。
Config 延遲生成
當 prop 生成且沒有對應的 .yml 檔案時,FMM 會自動建立一個預設 config 檔案,包含 isEnabled: true 和空的 scripts: 列表。這是非同步進行的,因此 prop 在首次生成時不會有 script -- 只有在 config 建立後並編輯新增 script 檔名之後才會生效。
這意味著:
- 將模型檔案放入
models/ - 生成 prop 一次(FMM 自動建立
.yml) - 編輯產生的
.yml新增你的 script 檔名 - 重新生成 prop 或重新載入伺服器(script 現在已啟用)
Hook 參考
每個 Lua prop script 檔案回傳一個表。該表中的每個鍵(除了 api_version 和 priority)必須是下面列出的 hook 之一。執行環境在對應的遊戲事件觸發時呼叫相符的函式。
| Hook | 觸發時機 | 說明 |
|---|---|---|
on_spawn | Prop 被生成到世界中 | Script 繫結時執行一次 |
on_game_tick | 每個伺服器 tick 一次(50 毫秒) | 僅在 script 定義了此 hook 時啟用 |
on_destroy | Prop 從世界中移除 | 清理 hook |
on_left_click | 玩家左鍵點擊(攻擊)prop | context.event 是傷害事件 |
on_right_click | 玩家右鍵點擊 prop | context.event 是互動事件 |
on_projectile_hit | 拋射物擊中 prop | context.event 是拋射物命中事件 |
on_zone_enter | 玩家進入監視區域 | 需要先設定區域監視 |
on_zone_leave | 玩家離開監視區域 | 需要先設定區域監視 |
最小檔案契約
每個 Lua prop script 必須 return 一個表。
必填和選填的頂層欄位
| 欄位 | 必填 | 類型 | 說明 |
|---|---|---|---|
api_version | 是 | Number | 目前必須為 1 |
priority | 否 | Number | 執行優先順序。較小的值先執行。預設為 0 |
| 支援的 hook 鍵 | 否 | Function | 必須使用 Hook 參考中列出的精確 hook 名稱之一 |
驗證規則
- 檔案必須回傳一個表。
api_version為必填,目前必須為1。priority如果存在必須為數字。- 每個額外的頂層鍵必須是受支援的 hook 名稱。
- 每個 hook 鍵必須指向一個函式。
- 未知的頂層鍵會被拒絕。
輔助函式和區域常數應放在最後的 return 上方,而不是在回傳的表內部。
一步步建構你的第一個可運作的 Prop Script
步驟 1 之前:設定 Config
- 將模型檔案(例如
my_prop.fmmodel)放入plugins/FreeMinecraftModels/models/ - 生成 prop 一次以產生
.ymlconfig - 在
plugins/FreeMinecraftModels/scripts/first_test.lua建立你的 script 檔案 - 編輯
plugins/FreeMinecraftModels/models/my_prop.yml:
isEnabled: true
scripts:
- first_test.lua
- 重新生成 prop 或重新載入伺服器
步驟 1:讓檔案載入
return {
api_version = 1,
on_spawn = function(context)
end
}
如果這在主控台中無錯誤地載入,你證明了:
- 檔案是有效的 Lua
- FMM 在
scripts/資料夾中找到了它 - Config 正確引用了它
- 回傳表的結構正確
步驟 2:讓 Prop 做一件可見的事
return {
api_version = 1,
on_spawn = function(context)
context.log:info("Prop script loaded for: " .. (context.prop.model_id or "unknown"))
end
}
檢查伺服器主控台。如果你看到日誌訊息,說明你的 hook 正在觸發。
步驟 3:回應玩家點擊
return {
api_version = 1,
on_right_click = function(context)
context.log:info("Prop was right-clicked!")
end
}
在遊戲中右鍵點擊 prop。如果主控台顯示訊息,說明點擊 hook 正在運作。
步驟 4:取消傷害使 Prop 無敵
return {
api_version = 1,
on_left_click = function(context)
if context.event then
context.event.cancel()
end
end
}
這是預製 invulnerable.lua script 使用的模式。它取消傷害事件,使 prop 底層的 armor stand 無法被摧毀。
步驟 5:點擊時播放動畫
return {
api_version = 1,
on_right_click = function(context)
context.prop:play_animation("open", true, false)
end
}
這會在 prop 模型上播放 "open" 動畫,帶有混合且不循環。
什麼是 context?
每個 hook 函式接收一個名為 context 的參數。把它想像成一個工具箱,FMM 在每次發生事件時交給你 -- 它包含了你與 prop、世界、區域等互動所需的一切。
on_right_click = function(context)
-- context.prop = 被點擊的 prop
-- context.event = 點擊事件(可以取消)
-- context.world = 粒子、聲音、方塊查詢工具
-- context.state = 你自己的持久儲存
-- context.log = 主控台日誌
-- context.scheduler = 延遲和重複任務
-- context.zones = 空間區域的建立和監視
end
你不需要自己建立 context -- FMM 會建立它並傳遞給你的 hook。
context 在每次 hook 呼叫時都會重新建立,除了 context.state,它在 prop 的整個生命週期中持續存在。這意味著你可以將資料儲存在 context.state 中,稍後在不同的 hook 中讀取。
關鍵 context API
以下是可用功能的摘要。完整詳情請參見 Prop API。
-
context.prop-- Prop 實體。提供model_id、current_location、play_animation()和stop_animation()。 -
context.event-- 觸發此 hook 的 Bukkit 事件。在on_left_click、on_right_click和on_projectile_hit中可用。提供cancel()、uncancel()和is_cancelled。在沒有事件的 hook 中(如on_spawn和on_game_tick)為nil。 -
context.state-- 在 prop 生命週期內持續存在的普通 Lua 表。用於儲存旗標、切換狀態、任務 ID 以及需要在 hook 之間記住的任何內容。 -
context.log-- 透過log:info(msg)、log:warn(msg)和log:error(msg)進行主控台日誌記錄。 -
context.scheduler-- 透過scheduler:run_later(ticks, callback)和scheduler:run_repeating(delay, interval, callback)實現延遲和重複任務。回呼接收全新的 context。透過scheduler:cancel(taskId)取消任務。 -
context.world-- 世界互動:粒子、聲音、方塊查詢、閃電、附近實體。完整方法列表請參見 Prop API。 -
context.zones-- 建立和監視空間區域(球體、圓柱體、長方體)。完整方法列表請參見 Prop API。
方法語法:: vs .
在 Lua 中,object:method(arg) 是 object.method(object, arg) 的簡寫。FMM API 接受兩種形式:
context.log:info("hello")
context.log.info("hello") -- 相同效果
所有文件統一使用 :。
即拷即用的範本
最小的有效 Prop Script
return {
api_version = 1,
on_spawn = function(context)
end
}
無敵 Prop 範本
return {
api_version = 1,
on_left_click = function(context)
if context.event then
context.event.cancel()
end
end
}
互動式 Prop 範本
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
}
第一個實際工作流程
建構全新的 prop script 時,請按以下順序進行:
- 建立
.lua檔案並讓on_spawn正常運作。 - 將 script 檔名新增到 prop 的
.ymlconfig 中。 - 切換到你實際需要的 hook(例如
on_right_click)。 - 先新增一條日誌訊息,然後再新增動畫或特效。
- 新增一個真實的特效(動畫、聲音、粒子)。
- 只有在此之後,才新增輔助函式、state、scheduler 邏輯或區域。
這個順序能大幅簡化除錯,因為每次只改變一件事。
預製 Script
FMM 附帶一個預製的 Lua script:
invulnerable.lua-- 取消左鍵點擊傷害事件,使 prop 不可摧毀。這是最簡單實用的 prop script。
更多範例請參見 範例與模式 頁面。
Lua Sandbox
Prop script 在與 EliteMobs 相同的沙盒化 LuaJ 環境中執行。Sandbox 限制完全相同。已移除的全域變數和可用標準函式庫函式的完整列表請參見 EliteMobs Hooks & Lifecycle 頁面。
摘要:
- 已移除:
debug、dofile、io、load、loadfile、luajava、module、os、package、require - 可用: 所有
math.*、string.*、table.*函式、pairs、ipairs、type、tostring、tonumber、pcall、print等
print 會輸出到伺服器主控台,但建議使用 context.log:info(msg) 進行輸出。日誌訊息會以 script 檔名為前綴,便於追蹤是哪個 script 產生的訊息。
下一步
- Prop API --
context.prop、context.event、context.world、context.zones和context.scheduler的完整參考 - 範例與模式 -- 附帶詳解的完整可運行 script
- 疑難排解 -- 常見問題、除錯技巧和 QC 檢查清單
如果你同時在撰寫 EliteMobs 的 Lua 能力,共享 API(context.world、context.zones、context.scheduler、context.state、context.log)的運作方式完全相同。Boss 特有的 API 請參見 EliteMobs Lua 文件。