跳至主要內容

Lua 腳本:入門指南

本頁帶你從空白檔案開始,撰寫可運作的 FreeMinecraftModels 互動道具腳本,並學習鉤子、上下文、道具 API 及腳本檔案的基本結構。

熟悉基礎後,請繼續閱讀:

  • 道具 API — context.prop、context.event、context.world 及其他上下文 API
  • 範例與模式:可供學習與改寫的道具腳本,附有設定說明
  • 疑難排解 — 常見錯誤、除錯技巧及品質檢查清單
實驗性功能

Lua 道具腳本目前屬於實驗性功能。隨著 FreeMinecraftModels 開發,鉤子名稱、輔助方法及行為可能改變,請在正式伺服器使用前仔細測試。

與 EliteMobs Lua 的關係

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: 清單的預設設定。因此首次生成時沒有腳本,需要等待設定建立,再加入腳本檔名。

  1. 將模型放入 models/。
  2. 生成道具一次,讓 FMM 建立 .yml。
  3. 編輯 .yml,加入腳本檔名。
  4. 編輯 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之前:準備設定​

  1. 將 my_prop.fmmodel 等模型放在 plugins/FreeMinecraftModels/models/。
  2. 生成道具一次,以建立 .yml。
  3. 建立 plugins/FreeMinecraftModels/scripts/first_test.lua。
  4. 編輯 plugins/FreeMinecraftModels/models/my_prop.yml:
isEnabled: true
scripts:
- first_test.lua
  1. 儲存下方步驟 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
}

第一個實際工作流程​

從頭撰寫道具腳本時,按以下順序進行:

  1. 建立 .lua 並讓 on_spawn 運作。
  2. 將腳本檔名加入道具的 .yml。
  3. 改用實際需要的鉤子,如 on_right_click。
  4. 先加入日誌,再加入動畫或效果。
  5. 加入一個實際效果,如動畫、聲音或粒子。
  6. 最後再加入輔助函式、狀態、排程邏輯或區域。

每次編輯 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 文件。