跳至主要內容

Lua 腳本:入門指南

本頁將教你為 FreeMinecraftModels 道具或自訂物品撰寫第一個 Lua 腳本,從一個空白檔案一路到一個可運作的互動式腳本。讀完之後,你將理解鉤子、context、道具與物品 API,以及每個腳本檔案的通用架構。

熟悉基礎知識後,請繼續閱讀配套頁面:

  • 道具與物品 API -- context.propcontext.itemcontext.eventcontext.world 和其他 context API
  • 範例與模式 -- 可供學習和改寫的完整可運行道具與物品腳本
  • 疑難排解 -- 常見錯誤、除錯技巧和 QC 檢查清單
實驗性功能

Lua 道具腳本與物品腳本目前為實驗性功能。隨著 FreeMinecraftModels 的演進,鉤子名稱、輔助方法和行為仍可能發生變化,因此在正式伺服器上使用前請仔細測試。

與 EliteMobs Lua 的關係

FreeMinecraftModels 使用 MagmaCore Lua 執行環境。如果你已經在為 EliteMobs 撰寫 Lua 能力,核心概念——回傳一個表的腳本檔案、api_version、鉤子、context、狀態、冷卻、排程和沙盒——都會很熟悉。確切的鉤子與 context 方法名稱仍取決於各個外掛:

  • EliteMobs 的腳本運行在 Boss 上,擁有 on_boss_damaged_by_playeron_enter_combat 等鉤子。
  • FMM 道具腳本運行在道具上,擁有 on_right_clickon_left_clickon_zone_enter 等鉤子。
  • FMM 物品腳本運行在自訂物品上,擁有 on_equipon_attack_entityon_consumeon_game_tick 等鉤子。

本頁記載的 context.worldcontext.zonescontext.schedulercontext.statecontext.log API 是 FreeMinecraftModels/MagmaCore 的版本。EliteMobs NPC 腳本使用相同的通用 MagmaCore 表加上 context.npc;EliteMobs Boss 能力則對其中數個表使用 Boss 專屬的變體。本頁涵蓋的是 FMM 道具與物品特有的內容。


什麼是道具腳本

道具腳本是位於 plugins/FreeMinecraftModels/scripts/ 資料夾中的獨立 .lua 檔案。它們透過模型檔案旁邊的 YAML 配置檔案引用,並在道具被生成到世界中時執行。

道具腳本擅長什麼

道具腳本在以下場景中表現出色:

  • 回應玩家點擊的互動式道具(門、拉桿、按鈕)
  • 玩家無法破壞的無敵裝飾道具
  • 偵測玩家進入或離開區域的接近觸發器
  • 在互動或計時器觸發時播放動畫的道具
  • 被點擊或靠近時播放聲音的道具
  • 任何需要超越靜態裝飾的邏輯的道具行為

如果你的道具純粹是裝飾性的且不需要互動,則不需要腳本。


什麼是物品腳本

物品腳本使用與道具腳本相同的 .lua 檔案格式和相同的 scripts/ 資料夾。差別在於它們附加在自訂物品上——也就是在 YML 設定檔中設定了 material: 欄位的模型。道具腳本在道具實體被生成到世界中時執行,而物品腳本則在玩家裝備該自訂物品(主手、副手或護甲欄位)時執行,並在物品被卸下時停止。

物品腳本如何運作

  • 啟動: 當玩家裝備自訂 FMM 物品時會建立一個腳本實例。腳本是「每位玩家每種物品」的——每組(玩家、itemId)配對對應一個 ScriptInstance
  • 停止: 當物品被卸下(移出有效欄位、丟棄,或玩家離線)時,該腳本實例會被銷毀。
  • 物品辨識: 自訂物品是透過 fmm_item_id PDC(PersistentDataContainer)鍵來辨識的,這與道具的 model_id 不同。若要取得正確標記的物品,請使用 /fmm giveitem <id> 或管理員選單。
  • Context: 物品鉤子接收的 context 包含 context.playercontext.itemcontext.worldcontext.statecontext.schedulercontext.log,以及(在適用時)context.event

物品腳本擅長什麼

物品腳本在以下場景中表現出色:

  • 具有特殊能力的自訂武器(霜之劍、魔杖)
  • 具有獨特右鍵或 shift-點擊動作的工具
  • 帶有自訂效果的消耗品
  • 穿戴時具有被動效果的護甲
  • 追蹤使用次數或具有有限耐久度的物品
  • 任何超越原版機制的手持物品行為

本頁的目標讀者

本頁面面向三類讀者:

  • 已經了解 EliteMobs Lua 腳本,想學習 FMM 特有鉤子和 API 的人
  • Lua 腳本新手,需要完整且名稱精確的道具參考的人
  • 使用 AI 起草道具腳本,需要足夠細節來辨別 AI 是否編造了虛假內容的人

需要在撰寫有用的道具腳本之前成為一名完整的 Lua 開發者。對於大多數實用的道具腳本,你真正需要的只是:

  • 如何在回傳的表中放置有效的鉤子
  • 如何從 context 讀取值
  • 如何用 if ... then return end 提前退出
  • 如何精確呼叫幾個輔助方法

Lua 快速入門

你不需要成為 Lua 專家也能撰寫 FMM 腳本。大多數腳本只會用到少數幾個概念:變數local x = 5)、函式function foo() end)、if 檢查if x then ... end)、{key = value})和 nil(Lua 的「什麼都沒有」值)。語法很輕量——沒有分號、沒有大括號,只用 end 來結束區塊。

如需附有範例的完整逐步說明,請參閱 MagmaCore Lua 腳本引擎 — Lua 快速入門。該入門是所有 Nightbreak 外掛共用的,因此學一次就能處處適用。


檔案存放位置

腳本檔案

.lua 檔案放在中央 scripts 資料夾中:

plugins/
FreeMinecraftModels/
scripts/
invulnerable.lua
interactive_door.lua
proximity_sound.lua

FMM 在啟動時會發現 plugins/FreeMinecraftModels/scripts/ 中的所有 .lua 檔案。

在模型的 scripts: 清單中,為求清楚請寫上 .lua 副檔名。FMM 也接受不帶副檔名的項目,並在內部自動補上 .lua。但磁碟上的檔案仍必須以 .lua 結尾,且名稱仍區分大小寫。

模型檔案和配置檔案

每個模型檔案可以在同一目錄中有一個對應的 .yml 配置檔案:

plugins/
FreeMinecraftModels/
models/
torch_01.fmmodel
torch_01.yml <-- torch_01 的腳本配置
scripts/
invulnerable.lua <-- 被 torch_01.yml 引用

.yml 配置是連接模型與其腳本的橋樑。


配置檔案格式

模型檔案旁邊的 YAML 配置檔案有以下欄位:

isEnabled: true
voxelize: false
solidify: false
scripts:
- invulnerable.lua

對於自訂物品(玩家可以手持或裝備的模型),你還要設定 material 欄位,並可選擇性地設定 nameloreenchantments

isEnabled: true
material: DIAMOND_SWORD
name: "&bFrost Blade"
lore:
- "&7A sword forged in eternal ice"
- "&7Slows enemies on hit"
enchantments:
- "SHARPNESS,5"
- "UNBREAKING,3"
scripts:
- frost_sword.lua
欄位類型預設值說明
isEnabledbooleantrue此道具/物品的腳本是否啟用
scripts字串列表[]scripts/ 資料夾中 .lua 檔案的檔名
voxelizebooleanfalse將放置對齊到 90 度旋轉與方塊格線
solidifybooleanfalse在道具佔用範圍內放置只以封包送出的屏障方塊(需要 voxelize
materialstring""有效的 Bukkit Material 名稱(例如 DIAMOND_SWORD)。設定此欄位會把該模型變成玩家可以手持或裝備的自訂物品,並啟用物品腳本系統
namestring""自訂物品的顯示名稱。支援 & 顏色代碼
lore字串列表[]顯示在物品提示中的說明行。支援 & 顏色代碼
enchantments字串列表[]套用到物品上的附魔。格式:"ENCHANTMENT_NAME,LEVEL"(例如 "SHARPNESS,5"

你可以將多個腳本附加到同一個道具。每個腳本都是獨立的實例。

物品 ID 與腳本數量限制
  • 物品 ID 取自 YML 檔名去掉副檔名的部分。例如 frost_sword.yml 產生的物品 ID 是 frost_sword。這就是 /fmm giveitemfmm_item_id PDC 鍵所使用的 ID。
  • 物品只會從 scripts: 清單中繫結一個腳本。FMM 會依序檢查各項目,使用第一個能解析的腳本,然後忽略後續項目。與物品不同,道具會把每個能解析的清單項目都當成獨立實例執行。
  • 如果你省略 .lua 副檔名,系統會自動補上,因此在 scripts: 清單中 frost_swordfrost_sword.lua 是等價的。

配置延遲生成

當道具生成且沒有對應的 .yml 檔案時,FMM 會自動建立一個預設配置檔案,包含 isEnabled: true 和空的 scripts: 列表。這是非同步進行的,因此道具在首次生成時不會有腳本——只有在配置建立後並編輯新增腳本檔名之後才會生效。

這意味著:

  1. 將模型檔案放入 models/
  2. 生成道具一次(FMM 自動建立 .yml
  3. 編輯產生的 .yml 新增你的腳本檔名
  4. 重新生成道具或重新載入(腳本現在已啟用)

鉤子參考

每個 Lua 道具腳本檔案回傳一個表。該表中的每個鍵(除了 api_versionpriority)必須是下面列出的鉤子之一。運行時在對應的遊戲事件觸發時呼叫相符的函式。

鉤子觸發時機說明
on_spawn道具被生成到世界中腳本繫結時執行一次
on_game_tick每個伺服器 tick 一次(50 毫秒)僅在腳本定義了此鉤子時啟用
on_destroy道具從世界中移除清理鉤子
on_left_click玩家左鍵點擊(攻擊)道具context.event 是傷害事件
on_right_click玩家右鍵點擊道具context.event 是互動事件
on_zone_enter玩家進入監視區域需要先設定區域監視
on_zone_leave玩家離開監視區域需要先設定區域監視
保留的道具鉤子

目前的腳本驗證器會接受道具腳本中的 on_projectile_hit,但目前的執行環境還不會把拋射物命中派送給道具腳本。若要處理繫結在腳本化物品上的拋射物行為,請使用物品的 on_projectile_hit;若要在外掛端處理模型化實體的拋射物,請使用 Bukkit 的 ModeledEntityHitByProjectileEvent API。


物品鉤子參考

物品腳本就像道具腳本一樣回傳一個表,包含 api_version = 1 和鉤子函式。以下鉤子可用於物品腳本。所有物品鉤子都會接收帶有 context.playercontext.item 以及(在適用情況下)context.eventcontext

說明欄位列出底層的 Bukkit 事件族。Lua 包裝器不會暴露原始的 Bukkit 特定欄位,例如 targetblockprojectileitem;當你需要額外的上下文時,請使用 context.playercontext.event.player 以及實體/世界輔助查詢。

戰鬥鉤子

鉤子觸發時機說明
on_attack_entity玩家手持該物品攻擊實體context.event 是傷害事件
on_kill_entity玩家手持該物品殺死實體context.event 是死亡事件
on_take_damage玩家在裝備該物品時受到傷害context.event 是傷害事件
on_shield_block玩家用盾牌擋下傷害context.event 是傷害事件
on_shoot_bow玩家射箭context.event 是射箭事件
on_projectile_hit玩家射出的拋射物擊中某物context.event 是拋射物命中事件
on_projectile_launch玩家發射拋射物context.event 是拋射物發射事件

互動鉤子

鉤子觸發時機說明
on_right_click玩家手持該物品右鍵點擊context.event 是互動事件
on_left_click玩家手持該物品左鍵點擊context.event 是互動事件
on_shift_right_click玩家手持該物品按 Shift+右鍵點擊context.event 是互動事件
on_shift_left_click玩家手持該物品按 Shift+左鍵點擊context.event 是互動事件
on_interact_entity玩家手持該物品右鍵點擊實體context.event 是實體互動事件

裝備鉤子

鉤子觸發時機說明
on_equip物品被裝備(移入啟用的欄位)適合用來初始化狀態
on_unequip物品被卸下(移出啟用的欄位)適合用來清理
on_swap_hands玩家在主手與副手之間交換該物品context.event 是交換事件
on_drop玩家丟棄該物品context.event 是丟棄事件

公用鉤子

鉤子觸發時機說明
on_break_block玩家手持該物品破壞方塊context.event 是方塊破壞事件
on_consume玩家食用該物品(食物/藥水)context.event 是食用事件
on_item_damage物品受到耐久度損耗context.event 是物品損耗事件
on_fish玩家使用釣魚竿context.event 是釣魚事件
on_death玩家在裝備該物品時死亡context.event 是死亡事件

生命週期鉤子

鉤子觸發時機說明
on_game_tick物品被裝備期間的每個伺服器 tick請謹慎使用——每秒執行 20 次

最小檔案契約

每個 Lua 道具腳本必須 return 一個表。

必填和選填的頂層欄位

欄位必填類型說明
api_versionNumber目前必須為 1
priorityNumber若有提供會被驗證,但 FMM 目前不會依它排序腳本。道具依 scripts: 清單順序執行;物品只會繫結第一個有效的腳本
支援的鉤子鍵Function必須使用鉤子參考中列出的精確鉤子名稱之一

驗證規則

  • 檔案必須回傳一個表。
  • api_version 為必填,目前必須為 1
  • priority 如果存在必須為數字。
  • 每個額外的頂層鍵必須是受支援的鉤子名稱。
  • 每個鉤子鍵必須指向一個函式。
  • 未知的頂層鍵會被拒絕。
備註

priority 有助於讓腳本在各個以 MagmaCore 為基礎的執行環境間保持可移植性,但 FreeMinecraftModels 目前的執行順序是由設定決定的。請在模型的 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:讓檔案載入

return {
api_version = 1,

on_spawn = function(context)
end
}

如果這在主控台中無錯誤地載入,你證明了:

  • 檔案是有效的 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 腳本使用的模式。它取消傷害事件,使道具底層的盔甲架無法被摧毀。

步驟 5:點擊時播放動畫

return {
api_version = 1,

on_right_click = function(context)
context.prop:play_animation("open", true, false)
end
}

這會在道具模型上播放 "open" 動畫,帶有混合且不循環。


什麼是 context

每個鉤子函式接收一個名為 context 的參數。把它想像成一個工具箱,FMM 在每次發生事件時交給你——它包含了你與道具、世界、區域等互動所需的一切。

你不需要自己建立 context——FMM 會建立它並傳遞給你的鉤子。關於共用 context API(context.statecontext.logcontext.cooldownscontext.schedulercontext.worldcontext.zones)的完整說明,請參閱 MagmaCore Lua 腳本引擎頁面。


關鍵 context API

以下是可用功能的摘要。完整詳情請參見道具與物品 API

  • context.prop --(僅限道具腳本)道具實體。提供 model_idcurrent_locationplay_animation()stop_animation()

  • context.item --(僅限物品腳本)自訂物品。提供 idmaterial()get_amount()set_amount()consume()get_uses()set_uses()get_name()set_name()get_lore()set_lore()get_durability()get_durability_percentage()use_durability()use_durability_percentage()。完整詳情請參見道具與物品 API

  • context.player -- 由玩家驅動的鉤子中的玩家。物品腳本會從物品持有者解析出它;道具點擊鉤子與通用區域鉤子則從觸發的玩家解析。在道具生命週期鉤子、道具排程回呼,以及不涉及玩家的鉤子中為 nil

  • context.event -- 觸發此鉤子的 Bukkit 事件或玩家行為者的輕量包裝。在點擊、戰鬥、互動與通用區域鉤子中可用。提供 event.playeris_cancelled,以及在底層 Bukkit 事件可取消時的 cancel() / uncancel();它不會暴露 targetblockprojectileitem 等 Bukkit 專屬欄位。在沒有事件或玩家行為者的鉤子中(如 on_spawnon_game_tickon_equip)為 nil

  • 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


方法語法:: vs .

關於 Lua 中 :. 方法語法的說明,請參閱 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
}

最小的有效物品腳本

return {
api_version = 1,

on_equip = function(context)
end
}

帶有右鍵動作的物品範本

return {
api_version = 1,

on_right_click = function(context)
if not context.cooldowns:check_local("activate", 40) then return end

-- Your action here
context.player:send_message("&aItem activated!")
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. 只有在此之後,才新增輔助函式、state、排程器邏輯或區域。

這個順序能大幅簡化除錯,因為每次只改變一件事。


預製腳本

FMM 附帶四個預製的 Lua 腳本:

  • invulnerable.lua -- 取消左鍵點擊傷害事件,使道具不可摧毀。這是最簡單實用的道具腳本。
  • pickupable.lua -- 讓玩家透過攻擊道具三次來撿起它。每次攻擊都會在道具上播放受傷動畫,第三次攻擊時道具會被移除並掉落其放置物品供玩家撿取。
  • storage_double.lua -- 把道具變成一個大型儲物箱(54 格)。右鍵點擊會開啟持久化的物品欄 GUI。會播放開啟/關閉動畫與音效。內容會儲存在道具上,並在伺服器重啟後保留。道具被摧毀時,所有內容都會掉落。
  • storage_single.lua -- 與 storage_double 相同,但只有 3 列(27 格)而非 6 列。

更多範例請參見範例與模式頁面。


Lua 沙盒

道具腳本與物品腳本在與 EliteMobs 相同的沙盒化 LuaJ 環境中執行。沙盒限制完全相同。已移除的全域變數和可用標準函式庫函式的完整列表,請參閱 MagmaCore Lua 腳本引擎頁面。


下一步

  • 道具與物品 API -- context.propcontext.itemcontext.eventcontext.worldcontext.zonescontext.scheduler 的完整參考
  • 範例與模式 -- 附帶詳解的完整可運行道具與物品腳本
  • 疑難排解 -- 常見問題、除錯技巧和 QC 檢查清單