Lua 腳本:行為程式
行為程式會以 Lua 行為取代生物的原生 AI,由這些行為決定生物要往哪裡移動、看向何處、以哪個實體為目標,以及何時攻擊。EliteMobs 透過 MagmaCore 的 Mind 執行階段,在 Minecraft 原生的 Brain 系統上執行這些程式。
行為程式不是 Lua 能力。Lua 能力會回應 on_boss_damaged_by_player 等 Boss 事件;行為程式則每個 tick 執行一次,並掌控生物的移動控制權。一個 Boss 可以同時使用兩者:行為可以透過 on_mind_action 請 Boss 的能力執行某個動作。
在自訂 Boss 檔案中設定 behavior(詳見建立 Boss),或在該實體類型的生物屬性檔案中設定。behavior: native 會保留原版 AI。若伺服器版本不支援原生 Mind,EliteMobs 會在啟動時記錄 Native Mind interface is unavailable on this Minecraft version.。此時選擇了程式的自訂 Boss 不會生成,並記錄 Cannot spawn <boss file>: ...。若 Boss 的 behavior 指向不存在或無效的程式,無論在哪個版本都會以相同方式失敗。
檔案
行為檔案位於 plugins/EliteMobs/behaviors/。以下隨附檔案不存在時,EliteMobs 會將其寫入:
plugins/
EliteMobs/
behaviors/
basic_melee.lua
modules/
target.lua
pursuit.lua
melee.lua
wander.lua
- 位於任何名為
modules之資料夾內的.lua檔案是模組。其他所有.lua檔案都是程式。 - Boss 以相對於
behaviors/的路徑參照程式,例如basic_melee.lua或guards/patrol_guard.lua。 - EliteMobs 會在其 Mind 服務啟動時載入行為檔案。驗證失敗的檔案會被略過,主控台會記錄
Could not load behavior <file>或Could not load behavior module <file>以及原因。 - 程式與模組 ID 使用
elitemobs命名空間,例如elitemobs:behavior/basic_melee。ID 為小寫,可包含a-z、0-9、.、_與-,冒號之後還可使用/。兩個程式不能共用同一個 ID,而每個模組 ID 都應只由一個檔案宣告。 - 一個命名空間最多容納 256 個模組。一個模組最多可列出 32 個依賴項,一個程式最多可解析 64 個模組,而每個原始碼檔案的上限為 1,000,000 個字元。
其他 Lua 腳本的沙盒規則同樣適用。請參閱 Lua 沙盒。每個執行程式的生物都有自己的 Lua 環境,因此檔案層級的區域變數不會在生物之間共用。
程式檔案
程式檔案會回傳 ai.program { ... }:
return ai.program {
id = 'elitemobs:behavior/basic_melee', revision = 1,
modules = {
'elitemobs:behavior/target', 'elitemobs:behavior/pursuit',
'elitemobs:behavior/melee', 'elitemobs:behavior/wander'
},
budget = {
callback_micros = 2000, entity_micros = 4000, server_micros = 5000,
max_callbacks = 20, max_instructions = 12000, max_action_requests = 2
}
}
| 欄位 | 型別 | 說明 |
|---|---|---|
id | 字串 | 必填。含命名空間的 ID;位於 behaviors/ 的檔案使用 elitemobs:...。 |
revision | 正整數 | 必填。 |
modules | 字串陣列 | 選填。要加入程式的模組 ID,其記憶、感測器與行為都會併入程式。依賴項會在需要它們的模組之前載入。重複項目與循環依賴會被拒絕。 |
memories、sensors、behaviors | 表 | 選填。程式可以宣告自己的這些項目,格式與模組相同。 |
budget | 表 | 選填的軟性排程限制。請參閱預算。 |
runaway | 表 | 選填的單一回呼硬性限制。請參閱預算。 |
模組檔案
模組檔案會回傳 ai.module { ... },用來將可重複使用的記憶、感測器與行為組合在一起:
| 欄位 | 型別 | 說明 |
|---|---|---|
id | 字串 | 必填。含命名空間的模組 ID。 |
revision | 正整數 | 必填。 |
dependencies | 字串陣列 | 選填。此模組所需的其他模組 ID。 |
memories | 表 | 選填。請參閱記憶。 |
sensors | 陣列 | 選填。ai.sensor { ... } 項目。 |
behaviors | 陣列 | 選填。ai.behavior { ... } 項目。 |
sensors、behaviors、modules 與 dependencies 必須是沒有空缺也沒有具名鍵的純陣列。感測器、行為與記憶的名稱,在程式的所有模組之間都必須是唯一的。
記憶
記憶是具有型別的值,供感測器與行為針對同一隻生物共用。請以名稱逐一宣告:
memories = {
candidate = { type = 'uuid', persistent = false },
next_attack = 'integer'
}
| 型別 | Lua 值 |
|---|---|
string | 字串 |
boolean | 布林值 |
integer | 整數 |
number | 數字 |
uuid | UUID 字串 |
position | { world = 'world', x = 0, y = 64, z = 0 } |
不含冒號的名稱會被放入程式的命名空間。persistent 預設為 false;設為 true 時,該記憶會被標記為隨 Mind 的儲存狀態一起序列化。請透過 c.memory:get(name)、c.memory:set(name, value, ttl_ticks)、c.memory:forget(name) 與 c.memory:contains(name) 讀寫記憶。set 的第三個參數是選填的;有提供時,該值會在經過指定的 tick 數後到期。使用未宣告的名稱會引發錯誤。
感測器
感測器負責收集資訊,通常會存入記憶。感測器會在行為之前執行。
ai.sensor {
id = 'elitemobs:behavior/find_target', interval = 20,
sense = function(c)
local target = c.perception:nearest_player(35)
if target then c.memory:set('candidate', target.uuid, 21)
else c.memory:forget('candidate') end
end
}
| 欄位 | 型別 | 預設值 | 說明 |
|---|---|---|---|
id | 字串 | 必填。 | |
interval | 正整數 | 1 | 兩次執行之間的 tick 數。 |
sense | 函式 | 必填。接收 Mind 上下文。 |
感測器不能使用 c.actuator;從感測器呼叫致動器方法會引發錯誤。
行為
行為在持有其宣告的控制權期間,會對生物採取動作。
ai.behavior {
id = 'elitemobs:behavior/attack', priority = 10,
controls = { ai.controls.attack },
can_start = function(c) return c.perception:current_target() ~= nil end,
can_continue = function(c) return c.perception:current_target() ~= nil end,
tick = function(c)
local target = c.perception:current_target()
if target then c.actuator:attack(target) end
end
}
| 欄位 | 型別 | 預設值 | 說明 |
|---|---|---|---|
id | 字串 | 必填。 | |
priority | 整數 | 0 | 數字越小越優先。 |
controls | 陣列 | 無 | 此行為執行期間租用的控制權。 |
can_start | 函式 | 一律為 true | 必須回傳 true 或 false。 |
can_continue | 函式 | 與 can_start 相同 | 必須回傳 true 或 false。 |
start | 函式 | 無 | 行為開始時執行一次。 |
tick | 函式 | 必填。行為執行期間每個 tick 執行一次。 | |
stop | 函式 | 無 | function(c, reason);行為停止時執行。 |
生命週期
- 行為停止時會檢查
can_start。當它回傳true,且行為能租用所有宣告的控制權時,start便會執行。 - 行為執行期間的每個 tick(包括開始的那個 tick),都會先執行
can_continue。它回傳false時,行為會以原因completed停止;否則執行tick。 stop(c, reason)會收到completed、preempted、program_replaced、entity_removed、callback_failed或handle_closed其中之一。停止時會釋放行為的控制權,並中止其持有的移動、目標或攻擊。
can_continue、start 或 tick 中的 Lua 錯誤會讓行為以 callback_failed 停止。can_start 或 can_continue 回傳布林值以外的任何東西都會視為錯誤。每次失敗時,主控台都會記錄 Mind <program> callback <callback> failed with ...。
控制權
| 控制權 | 允許 |
|---|---|
ai.controls.move | c.actuator:move_to(...)、c.actuator:stop_moving() |
ai.controls.look | c.actuator:look_at(...) |
ai.controls.jump | c.actuator:jump() |
ai.controls.target | c.actuator:set_target(...)、c.actuator:clear_target() |
ai.controls.attack | c.actuator:attack(...) |
ai.controls.action | c.actions:request(...) |
ai.controls.use_item | 保留;Lua 致動器沒有物品方法。 |
每個控制權同一時間只屬於一個執行中的行為。priority 數字較小的行為會從數字較大的行為手中奪取控制權,被奪取的行為會以原因 preempted 停止。它無法奪取數字較小之行為所持有的控制權。優先度相同時,id 依字母順序排在前面的行為會取得控制權。在未持有對應控制權的情況下呼叫致動器方法會引發錯誤。c.actuator:stop_all() 只會停止該行為所持有的項目。
在隨附模組中,目標選擇使用優先度 5、近戰攻擊 10、追擊 20、閒置遊蕩 50,因此只要有目標存在,追擊就會從遊蕩手中取得移動控制權。
請求 Boss 動作
持有 ai.controls.action 的行為可以呼叫 c.actions:request(identifier, payload)。EliteMobs 會透過 on_mind_action 將請求傳送給 Boss 的 Lua 能力。識別碼必須是不超過 128 個字元的小寫命名空間鍵,例如 'elitemobs:slam'。承載資料最多可有 16 個項目,鍵為不超過 64 個字元的小寫字串,字串值的上限為 256 個字元;無效的識別碼或承載資料會引發錯誤。此呼叫會回傳 accepted、deferred 或 rejected;在同一個 tick 內超過程式 max_action_requests 的請求會回傳 deferred。承載資料格式請參閱 Mind 動作上下文。
預算
budget 設定軟性排程限制。當某隻生物在一個 tick 內達到其中一項限制時,Mind 執行階段會略過該生物在此 tick 剩餘的回呼,直到下一個 tick。已在執行中的回呼一定會執行完畢。
| 鍵 | 預設值 | 說明 |
|---|---|---|
callback_micros | 2000 | 執行時間超過此值的回呼,會結束該生物在此 tick 的回呼。 |
entity_micros | 4000 | 每隻生物每個 tick 的回呼總時間。 |
server_micros | 20000 | 所有 Mind 程式合計用掉這麼多時間後,該生物在此 tick 的回呼就會停止。 |
max_callbacks | 128 | 每隻生物每個 tick 的回呼次數。 |
max_action_requests | 8 | 每隻生物每個 tick 的動作請求次數;最多 64。 |
所有值都必須為正數,且 callback_micros 不得超過 entity_micros,entity_micros 也不得超過 server_micros。
runaway 設定會中斷單一回呼的硬性限制:
| 鍵 | 預設值 | 說明 |
|---|---|---|
cpu_micros | 50000 | 每個回呼的執行緒 CPU 時間。 |
max_instructions | 50000 | 每個回呼的 Lua 指令數。 |
budget 也接受 max_instructions,如隨附的 basic_melee.lua 所示。請在 budget 或 runaway 其中之一宣告,不要兩者都宣告。超過 runaway 限制的回呼,會像其他回呼錯誤一樣失敗。
後續步驟
- 建立 Boss:behavior -- 為 Boss 選擇程式
- Lua API 參考:Mind 程式上下文 -- 所有
c.memory、c.perception、c.actuator與c.actions方法 - 鉤子與生命週期 --
on_mind_action及其他 Lua 能力鉤子
