跳至主要内容

Lua Scripting:入門指南

本頁將教你為 FreeMinecraftModels prop 撰寫第一個 Lua script,從一個空白檔案一路到一個可運作的互動式 prop。讀完之後,你將理解 hook、context、Prop API 以及每個 prop script 檔案的通用架構。

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

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

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

與 EliteMobs Lua 的關係

FreeMinecraftModels 與 EliteMobs 共享同一個 Lua 引擎(Magmacore)。如果你已經在為 EliteMobs 撰寫 Lua 能力,核心概念 -- hook、contextapi_version、scheduler、區域和 sandbox -- 是相同的。差異在於:

  • EliteMobs 的 script 運行在 Boss 上,擁有 on_boss_damaged_by_playeron_enter_combat 等 hook。
  • FMM 的 script 運行在 prop 上,擁有 on_right_clickon_left_clickon_projectile_hit 等 hook。

context.worldcontext.zonescontext.schedulercontext.statecontext.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
欄位類型預設值說明
isEnabledbooleantrue此 prop 的 script 是否啟用
scripts字串列表[]scripts/ 資料夾中 .lua 檔案的檔名

你可以將多個 script 附加到同一個 prop。每個 script 都是獨立的實例。

Config 延遲生成

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

這意味著:

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

Hook 參考

每個 Lua prop script 檔案回傳一個表。該表中的每個鍵(除了 api_versionpriority)必須是下面列出的 hook 之一。執行環境在對應的遊戲事件觸發時呼叫相符的函式。

Hook觸發時機說明
on_spawnProp 被生成到世界中Script 繫結時執行一次
on_game_tick每個伺服器 tick 一次(50 毫秒)僅在 script 定義了此 hook 時啟用
on_destroyProp 從世界中移除清理 hook
on_left_click玩家左鍵點擊(攻擊)propcontext.event 是傷害事件
on_right_click玩家右鍵點擊 propcontext.event 是互動事件
on_projectile_hit拋射物擊中 propcontext.event 是拋射物命中事件
on_zone_enter玩家進入監視區域需要先設定區域監視
on_zone_leave玩家離開監視區域需要先設定區域監視

最小檔案契約

每個 Lua prop script 必須 return 一個表。

必填和選填的頂層欄位

欄位必填類型說明
api_versionNumber目前必須為 1
priorityNumber執行優先順序。較小的值先執行。預設為 0
支援的 hook 鍵Function必須使用 Hook 參考中列出的精確 hook 名稱之一

驗證規則

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

輔助函式和區域常數應放在最後的 return 上方,而不是在回傳的表內部。


一步步建構你的第一個可運作的 Prop Script

步驟 1 之前:設定 Config

  1. 將模型檔案(例如 my_prop.fmmodel)放入 plugins/FreeMinecraftModels/models/
  2. 生成 prop 一次以產生 .yml config
  3. plugins/FreeMinecraftModels/scripts/first_test.lua 建立你的 script 檔案
  4. 編輯 plugins/FreeMinecraftModels/models/my_prop.yml
isEnabled: true
scripts:
- first_test.lua
  1. 重新生成 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_idcurrent_locationplay_animation()stop_animation()

  • context.event -- 觸發此 hook 的 Bukkit 事件。在 on_left_clickon_right_clickon_projectile_hit 中可用。提供 cancel()uncancel()is_cancelled。在沒有事件的 hook 中(如 on_spawnon_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 時,請按以下順序進行:

  1. 建立 .lua 檔案並讓 on_spawn 正常運作。
  2. 將 script 檔名新增到 prop 的 .yml config 中。
  3. 切換到你實際需要的 hook(例如 on_right_click)。
  4. 先新增一條日誌訊息,然後再新增動畫或特效。
  5. 新增一個真實的特效(動畫、聲音、粒子)。
  6. 只有在此之後,才新增輔助函式、state、scheduler 邏輯或區域。

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


預製 Script

FMM 附帶一個預製的 Lua script:

  • invulnerable.lua -- 取消左鍵點擊傷害事件,使 prop 不可摧毀。這是最簡單實用的 prop script。

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


Lua Sandbox

Prop script 在與 EliteMobs 相同的沙盒化 LuaJ 環境中執行。Sandbox 限制完全相同。已移除的全域變數和可用標準函式庫函式的完整列表請參見 EliteMobs Hooks & Lifecycle 頁面。

摘要:

  • 已移除: debugdofileioloadloadfileluajavamoduleospackagerequire
  • 可用: 所有 math.*string.*table.* 函式、pairsipairstypetostringtonumberpcallprint
提示

print 會輸出到伺服器主控台,但建議使用 context.log:info(msg) 進行輸出。日誌訊息會以 script 檔名為前綴,便於追蹤是哪個 script 產生的訊息。


下一步

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

如果你同時在撰寫 EliteMobs 的 Lua 能力,共享 API(context.worldcontext.zonescontext.schedulercontext.statecontext.log)的運作方式完全相同。Boss 特有的 API 請參見 EliteMobs Lua 文件